使用const std :: unique_ptr for pimpl idiom

Den*_*kiy 17 c++ c++11 c++17

Herb Sutter在CppCon16的演讲中,他建议用const std::unique_ptr(约10分钟)写出pimpl习语.

这应该如何与移动构造函数/赋值一起使用?c ++ 17中有什么东西吗?我找不到任何东西.

Yak*_*ont 8

如果你的类应该永远不是空的,那么非const的唯一ptr(默认移动/分配)是不合适的.移动ctor和移动分配将清空rhs.

const唯一的ptr将禁用这些自动方法,如果你想移动,你将不得不在impl中写入它(以及外面的一点胶水).

我个人会用我想要的语义编写一个值ptr(然后让编译器编写粘合剂),但是从const unique_ptr开始听起来像第一遍一样合理.

如果你放松了永不空虚,并且几乎从不空洞,你现在必须推理许多方法的先决条件,以及可能的连锁错误.

这种技术的最大成本,即返回值的难度,随着C++ 17而消失.

  • 如果你从一个物体移出它假设处于部分形成的状态,那么它只能被分配和破坏,所以移动构造函数/分配不会破坏你的not_null保证.如果你愿意的话,你可以从gsl想出像not_null的smth来包装它. (2认同)

Max*_*kin 3

这如何与移动构造函数/赋值一起工作?

移动构造函数

如果满足以下任一条件,则类 T 的隐式声明或默认移动构造函数被定义为已删除:

  • T 具有无法移动的非静态数据成员(已删除、无法访问或不明确的移动构造函数)

const std::unique_ptr是这样的数据成员,因为const.

如果const删除,编译器会生成移动构造函数和赋值,但不会生成复制构造函数和赋值。


Herb 解释了他使用的原因const unique_ptr

非常量也可以工作,但它更脆弱,因为默认的移动语义可能不正确。

使用const成员它更加健壮,因为const成员必须在构造函数中初始化。并且const文档表明对象的实现不会改变,它不是State或Strategy设计模式。

  • 对我来说,最重要的是通过构造来表达生命周期,并获得正确的默认值(在这种情况下,默认情况下没有脆弱的移动)。您可以自己编写复制和移动操作,例如 `MyClass& operator=(const MyClass& that) { *pimpl = *that.pimpl; 返回*这个;}`。`Impl` 类仍然是可复制的,甚至是可移动的,并且您可以委托给它。当然,这只能完成 95% 的工作,并且不反对编写自己的“value_ptr”类型来自动进行深层复制/移动。 (6认同)