将 std::unique_ptr 类成员标记为 const

Posted

技术标签:

【中文标题】将 std::unique_ptr 类成员标记为 const【英文标题】:Marking std::unique_ptr class member as const 【发布时间】:2017-01-15 04:43:01 【问题描述】:

很多使用std::unique_ptr 管理类依赖关系的示例如下所示:

class Parent

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

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

我问是因为我还没有在示例中看到它,并且不知道这是故意的还是只是为了简洁/概括。

【问题讨论】:

扪心自问:如果是const,可以移出吗? 你是说有很多编译失败的例子?你展示的那个当然可以。特别是,_child(std::move(child)) 部分毫无意义。 尝试移动 const unique_ptr 将无法编译,因为复制被删除并且没有构造函数接受 const rvalue ref。 @IgorTandetnik 这根本不是我的意思——两个版本都编译得很好:) 问问自己:耶稣会做什么? 【参考方案1】:

是的,你可以这样做,这也是我在 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() 传递一个。

【讨论】:

【参考方案2】:

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

收益是微不足道的,因为_childprivate,因此只能从Parent 内部访问,因此可以破坏围绕更改_child 的不变量的代码量仅限于成员函数和朋友无论如何都需要能够保持不变量。

我无法想象收益会超过负面影响的情况,但如果您这样做,您当然可以按照自己的方式进行操作,而不会破坏程序的其他部分。

【讨论】:

好点。可能解释了为什么我以前在任何示例中都没有见过它!【参考方案3】:

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

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

【讨论】:

@nwp 为什么不呢?它不会尝试复制或移动 Parent 的实例。 @nwp 因为它通过移动的 non const child 构造了一个unique_ptr @IgorTandetnik 问题中没有任何内容表明Parent 必须是可移动的,并且可以移动。 不多,正如@nwp 所说,当前实现允许移动到 const unique_ptr 但这会阻止 Parent 的任何复制或移动操作,因为 const unique ptr 不允许这样做。 @nwp OP 询问使 _child 成为 const 成员的“意外副作用”可能是什么。渲染 Parent 不可移动是 OP 似乎没有预料到的副作用。

以上是关于将 std::unique_ptr 类成员标记为 const的主要内容,如果未能解决你的问题,请参考以下文章

模板类重载 std::bind 成员函数

std::auto_ptr 在我的模板类中编译,但不是 std::unique_ptr

如何在构造函数中为成员 unique_ptr 赋予默认值? [复制]

使用 std::unique_ptr 的 C++ Pimpl Idiom 不完整类型

本周小贴士#123: absl::optional和std::unique_ptr

std :: list可以包含不同的std :: unique_ptr ?