Marking std :: unique_ptr class member as const

Many examples of using std::unique_ptr to control ownership of class dependencies are as follows:

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

My question is, are there any unexpected side effects of marking _child member as const ? (Besides reset() , release() , etc. You cannot call on _child ).

I ask because I have not seen it in the example yet and am not doing it intentionally or simply for brevity / generality.

+8
c ++ c ++ 11 smart-pointers unique-ptr
source share
3 answers

Due to the nature of std::unique_ptr (the sole ownership of the object), it should not have any copy constructor. The move constructor (6) only accepts non-constant rvalue references, which means that if you try to make your _child const and move it, you will get a good compilation error :)

Even if the custom unique_ptr would refer to the rvalue-reference constant, that would not be possible to implement.

+6
source share

The disadvantages are similar to any const member: that assignment and transfer assignment operators do not work correctly (they will need to overwrite _child ), and that switching from the parent will not lead to theft of _child (performance error). It is also unusual to write such code, possibly confusing people.

The gain is marginal because _child is private and therefore can only be accessed internally by Parent , so the amount of code that can break invariants revolving around the _child change is limited by member functions and friends who should be able to maintain invariants anyway.

I can’t imagine a situation where the gain would outweigh the cons, but if you do, you can do it your own way without breaking other parts of the program.

+1
source share

Yes, you can do this, and this is what I regularly do when implementing user interface classes in 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 } 

This is exactly comparable to writing Ui::MyWidget *const ui in C ++ 03 code.

The above code creates a new object, but there is no reason not to pass it when using std::move() , as in the question.

+1
source share

All Articles