将 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
(性能错误)。也很少会写这样的代码,可能会让人迷惑。
增益很小,因为 _child
是 private
,因此只能从 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()
传递一个对象。
许多使用 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
(性能错误)。也很少会写这样的代码,可能会让人迷惑。
增益很小,因为 _child
是 private
,因此只能从 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()
传递一个对象。