在 C++11 之前,我会实现一个类 Foo,其中包含基类 Bar 的多态对象为:
struct Foo {
Bar* m_b;
Foo(Bar* b) : m_b(b) {}
};
按照 Scott Meyer 的建议,原始指针是不好的,我想以 C++11 的方式实现Foo
,但我不知道这会是什么样子。
我开始这样写
struct Foo {
std::unique_ptr<Bar> m_b;
Foo(std::unique_ptr<Bar> b) : m_b(std::move(b)) {}
};
但这有一个缺点,即b
必须动态分配。
那么实现包含多态对象的类的 C++11 方法是什么?
智能指针比原始指针更好的论点是基于所有权的。
资源的所有权应该从类型系统中明确,因为这是一件容易出错的事情,也是一件很难通过阅读代码来理解的事情。 将它嵌入到类型系统中后,您可以从类型中判断决定对象生存期的因素。
C++11 之前的代码要么不拥有Bar
(它不对其生命周期负责),要么您的代码泄露。
C++11 后的代码拥有Bar
并负责其生命周期。
如果您想要一种状态,其中Foo
基于可能复杂的运行时逻辑有条件地拥有Bar
,有时不需要,那么std
智能指针可能不是一个好主意。
想象一下,在汽车安全规则之前,你有一辆车。 它有一个按钮,可以将乘客从车上弹出。 这很有趣,只要你不按按钮,就是安全的。
现在汽车安全规则就在这里,你听到遵守它们"更好"。 你来到汽车安全问答环节,询问如何设置一个按钮,将乘客从车上弹出,并遵循这些汽车安全规则。 他们似乎不允许乘客弹射。 即使你在按钮上盖上盖子,也有关于"如果汽车发生事故并且按钮执行不正确怎么办"以及生命和肢体以及其他东西。
如何在车内安装弹出座椅并获得 5 星安全评级?
智能指针使所有权一目了然。 如果你的所有权很混乱,那么你必须澄清它才能使用智能指针。
有些情况会使复杂的所有权和生命周期语义变得合理化。 这些很少而且相距甚远,默认情况下使用智能指针,我们可以避免生命周期的复杂性,而不必每次都对其进行验证。
struct Foo {
std::unique_ptr<Bar> m_b;
Foo(std::unique_ptr<Bar> b) : m_b(std::move(b)) {}
};
这是一个更好的界面,因为Foo
的 ctor 清楚地表明它拥有所有权。 获取原始指针,然后将其包装在智能指针中,使界面不清楚。