将 std::unique_ptr class 成员标记为常量

Marking std::unique_ptr class member as const

许多使用 std::unique_ptr 管理 class 依赖项所有权的示例如下所示:

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

我的问题是将 _child 成员标记为 const 是否有任何意想不到的副作用? (除了确保不能在 _child 上调用 reset()release() 等)。

我问是因为我还没有在示例中看到它,也不知道这是故意的还是只是为了 brevity/generality。

由于 std::unique_ptr(对象的唯一所有权)的性质,它需要没有任何复制构造函数。 move constructor(6) 仅采用非 const 右值引用,这意味着如果您尝试制作 _child const 并移动它,您会得到一个很好的编译错误: )

即使自定义 unique_ptr 会采用 const 右值引用,也无法实现。

缺点与任何 const 成员一样:赋值和移动赋值运算符不能正常工作(它们需要您覆盖 _child)并且从父级移动不会窃取 _child(性能错误)。也很少会写这样的代码,可能会让人迷惑。

增益很小,因为 _childprivate,因此只能从 Parent 内部访问,因此可以打破围绕改变 [= 的不变量的代码量11=] 仅限于需要能够保持不变量的成员函数和朋友。

我无法想象利大于弊的情况,但如果你这样做了,你当然可以按照自己的方式去做,而不会破坏程序的其他部分。

是的,你可以这样做,这是我在 Qt 中实现 UI 类 时经常做的事情:

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
}

这完全可以与用 C++03 代码编写 Ui::MyWidget *const ui 相媲美。

上面的代码创建了一个新对象,但没有理由不像问题中那样使用 std::move() 传递一个对象。