我有一个类管理unique_ptr
的向量:
class Foo
{
public:
...
private:
std::vector<std::unique_ptr<SomeClass>> vec_;
};
我有另一个类Bar
,我想存储一些引用类型,引用向量中的对象。实现这一点的最合乎逻辑和最直观的方法是什么?
我能想到的有四种选择:
Bar
存储引用
struct Bar
{
Bar(std::unique_ptr<SomeClass>& ref) : ref_(ref) {}
std::unique_ptr<SomeClass>& ref_;
};
这很简单,但是如果不重新构造对象,就无法重置引用。这仍然是首选方法吗?
在Foo
和Bar
中同时使用shared_ptr
class Foo
{
public:
...
private:
std::vector<std::shared_ptr<SomeClass>> vec_;
};
struct Bar
{
std::shared_ptr<SomeClass> ref_;
};
这个问题在于,它意味着Foo
和Bar
对对象具有相等的所有权,即使Foo
应该具有所有权。但也许这没什么大不了的?我犹豫的原因是我读到只有在所有权真正平等的情况下才应该使用shared_ptr
。我还知道,与unique_ptr
相比,shared_ptr
带来了相当大的开销。
使用weak_ptr
来表明Bar
没有对象的所有权(但是,强制您在Foo
中仍然使用shared_ptr
(
struct Bar
{
std::weak_ptr<SomeClass> ref_;
};
对我来说,这是一个很好的方法。我能看到的唯一缺陷是,即使Foo
拥有唯一所有权,我们也必须在Foo
中使用shared_ptr
。
使用unique_ptr::get
获取Bar
存储的原始指针
struct Bar
{
SomeClass* ref_;
}
这是我最不喜欢的选择。我们使用智能指针的全部原因是为了避免使用原始指针。把它们用于引用智能指针这样简单的事情感觉很傻。
当考虑到性能和代码可维护性时,这些选项中的哪一个是首选的,还是主观的?
我们使用智能指针的全部原因是为了避免使用原始指针
否:我们使用智能指针的全部原因是为了避免使用拥有原始指针的。
请参阅C++核心指南:以供参考
R.3:一个原始指针(一个T*(是非拥有的
我们确实更喜欢智能指针来表示自己的资源。但是,它并不拥有资源,所以使用原始指针是可以的。
从最差到最好的选择:
-
Bar存储引用:如果您想重新放置它,请不要使用引用。你说你确实想重新密封它,所以这就结束了。尝试解决这个问题没有任何好处,它只会让你的代码更加令人惊讶,也不会更好。
-
在这两个位置都使用
shared_ptr
:如果您需要对象保持活动状态,只要存在对它的引用,就可以这样做。不要担心"平等所有权";,担心语义是否对您的程序有意义。你的工作是决定在
Foo::vec_
中重置指针是否应该破坏对象,而不是在C++中表达共产主义宣言。 -
使用
shared_ptr
加weak_ptr
:如果希望Bar
检测到对象已被销毁。优点是它很好地记录了关系,并且您不必担心在更新
Foo
和Bar
之间意外访问悬挂指针。
拥有一个非拥有的原始指针是完全可以的,只要你确信一旦它不再有效,你不会意外地取消引用。话虽如此,shared_ptr
的开销主要发生在构造函数和析构函数调用期间(+使用过的内存中的一些小开销,因为需要为通过shared_ptr
拥有的每个对象分配一个额外的控制块(,因此,只要你不关心内存的每一个字节,也不在任何地方按值传递shared_ptr
s,你就不太可能注意到任何显著的性能差异——因此,拥有对象的shared_ptr
和用于存储引用的weak_ptr
可能是一种更安全、更好的方法。