In Herb Sutter's talk at CppCon16 he suggested writing pimpl idiom with const std::unique_ptr (roughly 10 minutes in).
How is this supposed to work with move constructors/assignments? Is there something in c++17? I couldn't find anything.
In Herb Sutter's talk at CppCon16 he suggested writing pimpl idiom with const std::unique_ptr (roughly 10 minutes in).
How is this supposed to work with move constructors/assignments? Is there something in c++17? I couldn't find anything.
If your class is supposed to be never-empty, a non-const unique ptr (with default move/assigns) is not appropriate. The move ctor and move assign will both empty the rhs.
A const unique ptr will disable these automatic methods, and if you want move you will have to write it within the impl (and a bit of glue outside).
I would personally write a value ptr with the semantics I want (then let compiler write the glue), but starting with a const unique_ptr sounds reasonable as a first pass.
If you relax the never-empty, and make it almost never-empty, you now have to reason about preconditions of a lot of methods, and possible knock-on bugs.
The biggest cost of this technique, difficulty in returning values, goes away with C++17.
std::move.const unique ptr, your objects cannot be moved, and this problem cannot occur. By using a specific never_empty_ptr, your code cannot be empty, and this problem cannot occur. Hand-rolling a never-empty state into a class is, on the other hand, probably a bad idea.std::move" constraint on one's (presumably substandard) developers. All the good ones will leave as soon as they can find a better job, of course, but you'll have your 'never empty' guarantee while still allowing other teams to write efficient code. I'm struggling to imagine a reasonable use case for this idiom. It undoes in one fell swoop 90% of the massive increment in utility and performance offered by trading up from c++03 to c++11.How is this suppose to work with move constructors/assignments?
The implicitly-declared or defaulted move constructor for class T is defined as deleted if any of the following conditions are true:
- T has non-static data members that cannot be moved (have deleted, inaccessible, or ambiguous move constructors)
const std::unique_ptr is such a data member because of const.
If const is dropped the compiler generates the move constructor and assignment, but not the copying ones.
Herb explains why he uses const unique_ptr:
non-const can work too, but it is more brittle because default move semantics are probably incorrect.
With const member it is more robust because const members must be initialized in the constructor. And const documents that the implementation of the object does not change, it is not State or Strategy design pattern.
std::move on std::unique_ptr is absolutely correct and very much what we want - an efficient transfer of state, leaving the moved-from handle in a very well defined state - "invalid, do not touch". Disabling moves explicitly is one thing (one might wonder at the motives). Disabling them through cryptic use of const just looks to me like playfulness.MyClass& operator=(const MyClass& that) { *pimpl = *that.pimpl; return *this; }. The Impl class can still be copyable and even movable, and you can delegate to it. Of course that only gets you 95% of the way, and there's no objection to also writing your own value_ptr type that automates the deep copy/move too.
unique_ptras a container for pimpl. If you wanted it to be copyable, you'd have to implement that in terms of a clone operation of course.const unique_ptrwould become a limitation very quickly.constpimpl can still be moved.const unique_ptris moveable. There is noconst unique_ptr&&constructor. If you can provide example code I'd be intrigued. I think you'd have to write a move-constructor that moves the implementation. That still leaves one object in an undefined state. It was noteworthy that he offered no use cases of theconst unique_ptr-as-pimpl (non)-idiom. Herb's a bright guy but he's not necessarily someone I'd follow blindly.