2015-12-17 20 views
12

std::unique_ptr::operator-> có chữ kýTại sao toán tử unique_ptr-> không bị quá tải?

pointer operator->() const noexcept; 

Vì vậy operator-> là const nhưng trả về một con trỏ có thể thay đổi. Điều này cho phép mã như:

void myConstMemberFunction() const 
{ 
    myUniquePtrMember->nonConstFunction(); 
} 

Tại sao tiêu chuẩn cho phép điều này và cách tốt nhất để ngăn việc sử dụng như được trình bày ở trên là gì?

+0

tôi mong đợi đó là bởi vì các nhà điều hành '.' không thể bị quá tải. – erip

+2

Trong C++ 'const' là cạn. Một 'int * const' cũng cho phép bạn sửa đổi đối tượng được trỏ tới. –

+4

Mã tương tự sẽ được cho phép nếu con trỏ không thông minh. Độ chói áp dụng cho con trỏ, không áp dụng cho con trỏ. – juanchopanza

Trả lời

17

Hãy suy nghĩ về nó như một con trỏ bình thường:

int * const i; 

là một con trỏ const đến một phi constint. Bạn có thể thay đổi int, nhưng không thay đổi con trỏ.

int const * i; 

là một phi const con trỏ đến một constint. Bạn có thể thay đổi con trỏ chứ không phải là số int.


Bây giờ, cho unique_ptr, đó là một câu hỏi liệu các const đi bên trong hoặc bên ngoài <>. Vì vậy:

std::unique_ptr<int> const u; 

giống như hình đầu tiên. Bạn có thể thay đổi int, nhưng không thay đổi con trỏ.

gì bạn muốn là:

std::unique_ptr<int const> u; 

Bạn có thể thay đổi con trỏ, nhưng không phải là int. Hoặc thậm chí:

std::unique_ptr<int const> const u; 

Ở đây bạn không thể thay đổi con trỏ hoặc các int.


Lưu ý cách tôi luôn đặt const ở bên phải? Đây là một ít phổ biến, nhưng là cần thiết khi giao dịch với con trỏ. Các const luôn luôn áp dụng cho điều ngay lập tức bên trái của nó, là * (con trỏ là const), hoặc int. Xem http://kuhllib.com/2012/01/17/continental-const-placement/.

Viết const int, có thể dẫn bạn đến suy nghĩ int const * là một số const-con trỏ đến số không constint, điều đó là sai.

7

Điều này lặp lại ngữ nghĩa của con trỏ truyền thống. Con trỏ const là con trỏ không thể bị biến đổi. Tuy nhiên, đối tượng nó trỏ đến có thể.

struct bar { 
    void do_bar() {} 
}; 

struct foo { 
    void do_foo() const { b->do_bar(); } // OK 
    bar* const b; 
}; 

Để tránh đột biến các pointee, bạn cần unique_ptr tương đương với con trỏ const để const, hoặc

const std::unique_ptr<const bar> b; 
Các vấn đề liên quan