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

std::unique_ptr attempting to reference a deleted function

本文关键字:删除 函数 引用 unique ptr std      更新时间:2023-10-16

我在Unity上工作了很长一段时间,回来后用Visual Studio 2015做了一些C++。我偶然发现了这个类定义

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

这个类是动态分配的,如下所示:

ObjPtr obj = ObjPtr(new A());

其中ObjPtr是定义的类型,看起来像:

typedef std::unique_ptr<A> objPtr;

并使用CCD_ 3将这些创建的对象添加到CCD_。有一次,我需要循环浏览对象列表,如果我找到了满足我的标准的东西,就保留它的副本

ObjPtr keep;
for(auto& object : GetObjectList() )
{
  if(/*check if its the object I want*/)
  {
    keep = object;
  }
}

其中GetObjectList返回一个const std::vector<ObjPtr>&

但我得到了一个"试图引用一个已删除的函数"。我在谷歌上搜索了一下,试图删除= delete部分,甚至评论了这两行。我甚至试着做

ObjPtr keep = std::move(object);

但我仍然得到删除的功能错误。有人能看到我做错了什么吗?或者给我一些可以帮助我的资源吗?

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

这里有几个替代方案(都有不同的效果):

  • keep的类型更改为非拥有的原始指针(也称为A *)并使用keep = object.get();。如果并且仅当您知道使用keep的时间不会超过ObjectList(或者更准确地说,使用地址的对象)的存在时间时,这是安全的。

  • std::unique_ptr移出容器,即使用keep = std::move(object);。当然,现在您在ObjectList中有一个缺口。(我知道你已经编辑了你的问题,说ObjectListconst,这意味着你不能修改,因此不能将对象从中移出。)

  • 如果希望共享所有权语义,请将ObjPtr的类型更改为std::shared_ptr<A>

  • 如果您绝对想要对象的副本,您可以向std::vector<ObjPtr>0添加一个virtual成员函数,该函数以多态方式克隆对象。

    class A
    {
    public:
      virtual std::unique_ptr<A> clone() = 0;
      …
    };
    

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

    不要使用keep = std::make_unique<A>(*object);,因为它不尊重对象的实际(动态)类型,并且总是切片到A。(由于你的A是不可复制的,它无论如何都不会工作。)

唯一指针之所以"唯一",是因为一个对象只能有一个这样的指针。如果您制作了一个唯一指针的副本,那么您将拥有两个分别拥有底层对象的东西。当每一个都被销毁时,对象就会被销毁,从而导致双重删除。

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