首页 > 解决方案 > 是否可以在 C++ 中的类和向量中存储一个 unique_ptr?

问题描述

我试图保存一个指向向量(来自一个Base类)和一个Derivated类对象的唯一指针,所以稍后我可以为所有人调用一个方法。但是我想从类中调用方法,Derivated所以我也需要为它们存储引用。

class Foo
{
     vector<unique_ptr<Base>> bar;
     unique_ptr<Derivated1> bar2;
     unique_ptr<Derivated2> bar3;
}

Foo::Foo(){
     this->bar2 = make_unique<Derivated1>();
     this->bar2->doSomethingDerivated1();
     this->bar3 = make_unique<Derivated2>();
     this->bar->push_back(move(bar2));
     this->bar->push_back(move(bar3));
}

Foo::callForAll() {
     for (const auto& foo: this->bar) foo->doSomethingBase();
}

Foo::callForDerivated1() {
     this->bar2->doSomethingDerivated1();
}

这样的事情可能吗?据我了解,此代码很可能会失败。会移动地方bar2bar3nullptr吗?创建一个unique_ptr,存储一个原始指针,bar2->get()然后push_back工作vector

注意:这些对象只属于这个类,所以唯一是有意义的。

标签: c++smart-pointers

解决方案


不,unique_ptr 的全部意义在于唯一。这意味着您无法复制它。

但是,您可以复制 unique_ptr 管理的基础指针。例如

unique_ptr<Foo> foo(new Foo);
Foo* foo_copy = foo.get();

执行此操作时需要注意几件事:

  1. 不要删除foo_copy. 这是 unique_ptr 的工作。如果您删除 foo_copy,那么您将犯下双重删除的罪过,它具有未定义的行为(即允许编译器生成发射核导弹的代码)。

  2. 不要使用foo_copyafter foohas been destroyed 因为 whenfoo被销毁,底层指针被删除(除非 foo 已经放弃了底层指针的所有权,并且底层指针还没有被其他方式删除)。这就是free后使用的罪过,它也有UB。

移动是 unique_ptr 放弃所有权的一种方式。一旦你移出一个 unique_ptr,它就不再指向任何东西(这就是移动的全部意义;当你从 A 走到 B 时,你不再在 A,因为只有你们一个人,而且你已经决定改为位于 B)。我相信尝试在空的 unique_ptr 上使用 -> 运算符调用方法也是 UB。

看起来你应该做的是

  1. vector<unique_ptr<Base>> v;
  2. Derived* ob = v[i].get();

让我重申,这有点危险和不寻常。

Tangent:我发现您没有使用虚拟方法非常可疑;virtual 真的应该是默认值(有点像 double 是默认值,而不是 float,即使 float 看起来是并且应该是默认值)。实际上,我发现您使用继承很可疑。继承是有史以来最被高估的功能之一。我怀疑这可能是您的麻烦的根源。例如,Go 语言甚至没有继承,但它确实具有多态性(即同一接口的不同实现)。

PS:请不要通过调用UB意外消灭人类。


推荐阅读