std :: unique_ptr尝试引用已删除的函数

dwn*_*enr 5 c++ c++11

我已经在Unity上工作了一段时间,然后回来使用Visual Studio 2015做一些C++.我遇到了这个类定义

class A
{
public:
  A();
  virtual ~A();
  A(const A&) = delete;
  A& operator=(const A&) = delete;

private:
  …
}
Run Code Online (Sandbox Code Playgroud)

此类动态分配如下:

ObjPtr obj = ObjPtr(new A());
Run Code Online (Sandbox Code Playgroud)

where ObjPtr是一个定义的类型,如下所示:

typedef std::unique_ptr<A> objPtr;
Run Code Online (Sandbox Code Playgroud)

并将这些创建的对象添加到std::vector<ObjPtr>使用中std::move.在一个点上,我需要遍历对象的列表,如果我找到的东西,满足我的标准,保持它的一个副本.

ObjPtr keep;

for(auto& object : GetObjectList() )
{
  if(/*check if its the object I want*/)
  {
    keep = object;
  }
}
Run Code Online (Sandbox Code Playgroud)

GetObjectList返回的位置const std::vector<ObjPtr>&.

但我得到了"试图引用删除的功能".我做了一些谷歌搜索并试图删除该= delete部分,甚至评论了2行.我甚至试图这样做

ObjPtr keep = std::move(object);
Run Code Online (Sandbox Code Playgroud)

但我仍然得到删除的功能错误.任何人都可以看到我做错了什么或指向一些可以帮助的资源吗?

5go*_*der 10

A std::unique_ptr无法复制.即使托管对象可以(但你的不能).

你有几个选择(都有不同的效果):

  • 将类型更改keep为非拥有原始指针(aka A *)并使用keep = object.get();.这是安全的,当且仅当你知道你不会使用keep长于ObjectList(或者更准确地说,你把地址的对象)的存在.

  • 移动std::unique_ptr从容器中,即使用keep = std::move(object);.当然,现在你有一个差距ObjectList.(我知道你已经编辑你的问题说ObjectListconst,这意味着你不能修改,因此无法移动的物体出来.)

  • 改变的类型ObjPtrstd::shared_ptr<A>,如果你想共享所有权的语义.

  • 如果你绝对想要一个对象的副本,你可以添加一个virtual成员函数,以A多态方式克隆该对象.

    class A
    {
    public:
      virtual std::unique_ptr<A> clone() = 0;
      …
    };
    
    Run Code Online (Sandbox Code Playgroud)

    然后,您可以在class派生自的每个叶子中实现该功能A.在循环中,然后使用keep = object->clone();.为此,您可能想要制作复制构造函数,protected但不要这样做delete.

    不要使用,keep = std::make_unique<A>(*object);因为它不会尊重对象的实际(动态)类型,并始终切片到A.(因为你A的副本不可复制,所以无论如何都不行.)


Dav*_*rtz 5

唯一指针之所以“唯一”,是因为指向一个对象只能存在一个这样的指针。如果您制作了唯一指针的副本,那么您将拥有两个事物,每个事物都拥有基础对象。当每一个被销毁时,该对象都会被销毁,从而导致双重删除。

如果您需要多个所有权,请使用shared_ptr. 如果您不需要保留副本的代码的所有权,则不要保留副本,而是保留指针或引用。