2012-01-10 38 views
14

Tôi hiểu rằng một con trỏ const thể được khai báo một vài cách sau:C++: Const đúng đắn và con trỏ đối số

const int * intPtr1; // Declares a pointer that cannot be changed. 
int * const intPtr2; // Declares a pointer whose contents cannot be changed. 

// EDIT: THE ABOVE CLAIMS ARE INCORRECT, PLEASE READ THE ANSWERS. 

Nhưng những gì về các nguyên tắc tương tự trong bối cảnh các đối số chức năng?

tôi sẽ giả định rằng sau là không cần thiết:

void someFunc1(const int * arg); 
void someFunc2(int * arg); 

Kể từ someFunc 1 và 2 làm một pass-by-giá trị cho con trỏ chính nó, không thể của nó cho someFunc1 để thay đổi giá trị của con trỏ gốc, trong một cuộc gọi cụ thể cho hàm. Để minh họa:

int i = 5; 
int * iPtr = &i; 

someFunc1(iPtr); // The value of iPtr is copied in and thus cannot be changed by someFunc1. 

Nếu điều này là đúng, thì không có điểm nào khai báo hàm có 'const int * ptr' loại arg, đúng không?

+13

Bạn có khai báo sai vòng. "const int *" là một con trỏ có thể thay đổi thành một int không thay đổi được. "int * const" là một con trỏ không thể thay đổi thành int có thể thay đổi. –

+3

Không, bạn có nó ngược. –

+4

Đã chỉnh sửa câu hỏi để kích hoạt các nhân viên cứu hộ vui vẻ sẽ không bị phát hiện sai. Tôi đã để lại sai lầm để các câu trả lời vẫn có ngữ cảnh đó. – Ben

Trả lời

25

Bạn có nó ngược:

const int * intPtr1; // Declares a pointer whose contents cannot be changed. 
int * const intPtr2; // Declares a pointer that cannot be changed. 

sau đây const là thực sự không cần thiết, và không có lý do gì để đặt nó trong một hàm khai:

void someFunc1(int * const arg); 

Tuy nhiên, bạn có thể muốn đặt nó vào chức năng triển khai, vì lý do tương tự mà bạn có thể muốn khai báo biến cục bộ (hoặc bất kỳ thứ gì khác) const - việc triển khai có thể dễ dàng hơn để theo dõi khi bạn biết rằng một số thứ sẽ không thay đổi. Bạn có thể làm điều đó cho dù có được khai báo là const trong bất kỳ khai báo nào khác của hàm hay không.

+0

Bây giờ tôi trông giống như một kẻ ngốc ... Cảm ơn lời giải thích ngắn gọn và khẳng định rằng có thực sự là một const không cần thiết trong một trong những định nghĩa đó! – Ben

+0

có sự khác biệt nào giữa 'const int * intPtr1' và' int const * intPtr1; '? – dynamic

+5

@ yes123: Không có sự khác biệt nào cả. 'const' đủ điều kiện trước khi nó, trừ khi nó ở đầu, trong trường hợp đó nó hội đủ điều kiện đầu tiên. Vì vậy, trong cả hai trường hợp, nó đủ điều kiện 'int', không phải con trỏ. 'int * const' sẽ đủ điều kiện con trỏ. –

2

Có, bạn là chính xác (bỏ qua thực tế là bạn đã cho họ một cách sai lầm xung quanh) - không có ý nghĩa khi tham số không tham chiếu const. Ngoài ra, không có ý nghĩa trong việc trả về giá trị không tham chiếu const.

+0

Giá trị trả về 'const' không tham chiếu thậm chí có hại. – Xeo

+0

@Xeo: Bạn có thể giải thích về điều đó không? Tôi không biết họ có hiệu lực gì cả! – ruakh

+0

@ruakh: Xem [Khi nào một kiểu trả về const can thiệp vào việc khởi tạo mẫu?] (Http://stackoverflow.com/questions/2926319/when-does-a-const-return-type-interfere-with-template-instantiation) Đó là một vấn đề khá nhỏ. –

22

Điều đó không có nghĩa đối với người gọi nhưng đối với mã bên trong someFunc1. Vì vậy, bất kỳ mã nào bên trong someFunc1 sẽ không vô tình thay đổi mã đó. như

void someFunc1(int *arg) { 
    int i = 9; 
    arg = &i; // here is the issue 
    int j = *arg; 
} 

Cho phép làm một số nghiên cứu trường hợp:

1) Chỉ cần làm cho giá trị const nhọn

void someFunc1(const int * arg) { 
int i = 9; 
*arg = i; // <- compiler error as pointed value is const 
} 

2) Chỉ cần làm cho con trỏ const

void someFunc1(int * const arg) { 
int i = 9; 
arg = &i; // <- compiler error as pointer is const 
} 

3) Cách đúng để sử dụng const nếu các biến có liên quan có thể là const:

void someFunc1(const int * const arg) { 
    int i = 9; 
    *arg = i; // <- compiler error as pointed value is const 
    arg = &i; // <- compiler error as pointer is const 
} 

Điều này sẽ làm rõ mọi nghi ngờ. Vì vậy, tôi đã đề cập nó có nghĩa là cho mã chức năng và không cho người gọi và bạn nên sử dụng hạn chế nhất trong 3 trường hợp tôi đã đề cập ở trên.

EDIT:

  • Ngay cả trong tờ khai chức năng của mình một thói quen tốt để khai báo const. Điều này sẽ không chỉ tăng khả năng đọc mà còn là người gọi sẽ nhận thức được hợp đồng và có thêm sự tự tin về bất biến của các đối số. (Đây là yêu cầu bcoz bạn thường chia sẻ tập tin tiêu đề của bạn để người gọi có thể không thực hiện c/cpp tập tin của bạn)
  • Ngay cả trình biên dịch có thể chỉ ra tốt hơn nếu cả hai tuyên bố và định nghĩa được đồng bộ.
+0

Nhưng điều đó không giải thích tại sao bạn sẽ viết 'void someFunc1 (const int * arg);'. Lưu ý rằng predeclaring 'someFunc1' như' void someFunc1 (int * arg); 'vẫn cho phép bạn định nghĩa nó là' void someFunc1 (int * const arg) {...} 'nếu bạn muốn; 'const'-ness của biến tham số không ảnh hưởng đến chữ ký hàm thực tế. – ruakh

+0

@ruakh xin vui lòng đi qua ans cập nhật. Đó sẽ là mối quan tâm của bạn. – havexz

+0

Rất tiếc, không, câu trả lời cập nhật của bạn vẫn không trả lời được câu hỏi. (Xem câu trả lời của Mike Seymour, ở trên, để có câu trả lời chính xác.) – ruakh

6

Bạn có logic của mình theo cách không đúng. Bạn nên đọc loại ngược, do đó, const int * là một con trỏ đến một số const intint * const là một con trỏ const đến một int.

Ví dụ:

void foo() { 
    int a = 0; 
    int b = 0; 

    int * const ptrA = &a; 
    *ptrA = 1; 
    ptrA = &b; ///< Error 

    const int * ptrB = &a; 
    *ptrB = 1; ///< Error 
    ptrB = &b; 

    const int * const ptrC = &a; 
    *ptrC = 1; ///< Error 
    ptrC = &a; ///< Error 
} 

Xây dựng và hiển thị tại sao bạn muốn tham số chức năng của bạn trở thành một const int * bạn có thể muốn chỉ ra cho người gọi rằng họ phải vượt qua trong một int bởi vì bạn là một hàm muốn thay đổi giá trị. Hãy xem xét mã này ví dụ:

void someFunc1(const int * arg) { 
    // Can't change *arg in here 
} 

void someFunc2(int * arg) { 
    *arg = 5; 
} 

void foo() { 
    int a = 0; 
    someFunc1(&a); 
    someFunc2(&a); 

    const int b = 0; 
    someFunc1(&b); 
    someFunc2(&b); ///< *** Error here. Must pass in an int not a const int. 
} 
2

Bạn có nó một cách sai lầm:

const int * intPtr1; // Declares a pointer whose contents cannot be changed. 
int * const intPtr2; // Declares a pointer that cannot be changed. 

Nói chung nó dễ dàng hơn để lý do về constness khi writting biểu thức hơi khác nhau: const int* là loại giống như int const *. Trong ký hiệu rằng các quy tắc là rõ ràng hơn nhiều, const luôn áp dụng đối với các loại trước nó, do đó:

int const * intPtr1; // Declares a pointer to const int. 
int * const intPtr2; // Declares a const pointer to int. 
int const * * const * complexPtr; // A pointer to const pointer to pointer to const int 

Khi loại được viết với một const hàng đầu, các const được xử lý như thể nó đã được viết sau khi loại đầu tiên , do đó, const T* sẽ trở thành T const *. do đó

void someFunc2(int * arg); 

Không phải là thừa, vì someFunc2 có thể thay đổi các nội dung của arg, trong khi someFunc1 có thể không. void someFunc3(int * const arg); sẽ là dự phòng (và không rõ ràng) mặc dù

Các vấn đề liên quan