2015-12-17 12 views
12

std::unique_ptr::operator-> hat die UnterschriftWarum ist unique_ptr operator-> nicht const-überladen?

pointer operator->() const noexcept; 

So operator-> const ist aber eine veränderbare Zeiger zurückgibt. Dies ermöglicht Code wie:

Warum lässt der Standard dies zu, und was ist der beste Weg, um die Verwendung wie oben dargestellt zu verhindern?

+0

ich es, weil der Betreiber 'erwartet .' nicht überlastet werden kann. – erip

+2

In C++ ist 'const' flach. Mit einem 'int * const 'können Sie auch das auf das Objekt angegebene Objekt ändern. –

+4

Der gleiche Code wäre zulässig, wenn der Zeiger nicht intelligent wäre. Die Konstante gilt für den Zeiger, nicht für den Zeiger. – juanchopanza

Antwort

17

Denken Sie darüber nach wie ein normaler Zeiger:

int * const i; 

ist ein const Zeiger auf eine nicht constint. Sie können die int, aber nicht den Zeiger ändern.

int const * i; 

ist ein nicht-const Zeiger auf eine constint. Sie können den Zeiger aber nicht die int ändern.


Nun, für unique_ptr, es ist eine Frage, ob die const geht innerhalb oder außerhalb des <>. Also:

std::unique_ptr<int> const u; 

ist wie der erste. Sie können die int, aber nicht den Zeiger ändern.

Was Sie wollen, ist:

std::unique_ptr<int const> u; 

Sie den Zeiger ändern kann, aber nicht die int. Oder vielleicht sogar:

std::unique_ptr<int const> const u; 

Hier können Sie den Zeiger nicht ändern oder die int.


Beachten Sie, wie ich die const auf der rechten Seite immer diese Stelle setzen? Dies ist etwas ungewöhnlich, ist aber im Umgang mit Zeigern notwendig. Die const gilt immer für das Ding unmittelbar links davon, sei das die * (Zeiger ist const) oder die int. Siehe http://kuhllib.com/2012/01/17/continental-const-placement/.

const int Schreiben, könnten Sie führen int const * zu denken ist ein const -Zeiger zu einem nicht constint, was falsch ist.

7

Dies repliziert die Semantik von traditionellen Zeigern. Ein Zeiger const ist ein Zeiger, der nicht mutiert werden kann. Das Objekt, auf das es zeigt, kann jedoch.

struct bar { 
    void do_bar() {} 
}; 

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

die pointee mutiert zu vermeiden, müssen Sie den unique_ptr Äquivalent const Zeiger auf const oder

const std::unique_ptr<const bar> b;