2016-09-07 25 views
8

Wiele przykładów korzystania std::unique_ptr zarządzać własności zależności klasy wyglądać następująco:Znakowanie std :: unique_ptr członkiem klasy jako const

class Parent 
{ 
public: 
    Parent(Child&& child) : 
    _child(std::make_unique<Child>(std::move(child))){} 
private: 
    std::unique_ptr<Child> _child; 
}; 

Moje pytanie brzmi, czy oznaczenie elementu _child jak const mieć dowolny nieoczekiwane efekty uboczne? (Poza zapewnieniem, że reset(), release() itp. Nie można wywołać na _child).

Pytam, ponieważ nie widziałem go jeszcze w tym przykładzie i nie wiem, czy jest to celowe, czy tylko dla zwięzłości/ogólności.

+1

Zadaj sobie pytanie: Jeśli jest "const", czy można go przenieść z? – NathanOliver

+1

Mówisz, że istnieje wiele przykładów, które nie dają się skompilować? Ten, który pokazujesz, z pewnością robi. W szczególności część "_child (std :: move (child))" nie ma sensu. –

+4

Próba przeniesienia 'const' unique_ptr nie powiedzie się, ponieważ kopiowanie zostało usunięte i nie ma konstruktora, który pobiera wartość stałą r. –

Odpowiedz

6

Ze względu na charakter std::unique_ptr (wyłączna własność obiektu) wymagane jest, aby nie mieć konstruktora kopiowania. move constructor (6) zajmuje tylko non-const rvalue odniesień, co oznacza, że ​​jeśli chcesz spróbować dokonać _childconst i przenieść go chcesz uzyskać ładny błąd kompilacji :)

Nawet jeśli zwyczaj unique_ptr zajęłoby wartość rvalue-reference nie byłaby możliwa do wdrożenia.

+0

Dlaczego [to] (http: // ideone.com/Mu1Ke9) skompilować? – nwp

+0

@nwp Dlaczego tak nie jest? Nie próbuje kopiować ani przenosić instancji typu "Parent". –

+0

@ nwp, ponieważ konstruuje 'unique_ptr' przez przeniesiony * non * const' child'. –

1

Wady są jak w przypadku każdego członka const: To przyporządkowanie i przenieść przypisanie operatorzy nie działa prawo (oni wymagać, aby zastąpić _child) oraz że przejście od rodzica nie ukraść _child (błąd wydajności) . Również niezbyt często pisze się taki kod, prawdopodobnie dezorientując ludzi.

Zysk jest marginalne, ponieważ _child jest private i dlatego mogą być dostępne tylko od wewnątrz Parent, więc ilość kodu, który może złamać niezmienniki obracające się wokół zmienia _child jest ograniczone do funkcji składowych i przyjaciół, które muszą być w stanie utrzymać niezmiennie w każdym razie.

Nie mogę sobie wyobrazić sytuacji, w której zysk przeważy nad wadami, ale jeśli to zrobisz, z pewnością możesz zrobić to po swojemu, bez zerwania innych części programu.

+0

Dobre punkty. Prawdopodobnie wyjaśnia, dlaczego nie widziałem go wcześniej w żadnych przykładach! –

1

Tak, można to zrobić, i to, co mam robić regularnie podczas realizacji zajęć UI w Qt:

namespace Ui { 
    class MyWidget 
} 

class MyWidget : public QWidget 
{ 
    Q_OBJECT 

    const std::unique_ptr<Ui::MyWidget> ui; 

public: 
    explicit MyWidgetQWidget *parent = 0) 
     : ui(new Ui::MyWidget{}) 
    { 
    } 

    ~MyWidgetQWidget(); 
    // destructor defined as = default in implementation file, 
    // where Ui::MyWidget is complete 
} 

To dokładnie porównywalne do pisania Ui::MyWidget *const ui w kod C++ 03.

Powyższy kod tworzy nowy obiekt, ale nie ma powodu, aby go nie ominąć podając std::move() jak w pytaniu.

Powiązane problemy