【问题标题】:What do I Need to Return an Object with a unique_ptr Member?我需要什么才能返回具有 unique_ptr 成员的对象?
【发布时间】:2019-03-03 14:48:12
【问题描述】:

假设我有这个对象:

struct foo {
    std::unique_ptr<int> mem;
    virtual ~foo() = default;
};

我无法再返回在函数中创建的 foo 对象:

foo make_foo() {
    foo result;

    result.mem = std::make_unique<int>({});
    return result;
}

正如可能表明的那样,我需要析构函数是虚拟的,因为这将是一个基类。但是即使我使用默认的析构函数,这还不够,我仍然无法返回在函数中创建的对象。

我得到错误:

error C2280: foo::foo(const foo &): attempting to reference a deleted function

有没有办法解决这个问题?

【问题讨论】:

  • 尝试添加foo() = default;foo(foo &amp;&amp;) = default;foo &amp;operator=(foo &amp;&amp;) = default;。如果您已经定义了移动赋值运算符复制构造函数/赋值运算符或析构函数,则不会隐式生成移动构造函数。
  • @user463035818 最后一条错误消息是 /usr/include/c++/6/bits/unique_ptr.h:359:7:注意:在此处声明 unique_ptr(const unique_ptr&) = delete;
  • @NathanOliver 哦,对了,我太习惯于先解决第一件事,所以我忽略了它

标签: c++ return copy-constructor unique-ptr virtual-destructor


【解决方案1】:

[class.copy.ctor]/8

如果类 X 的定义没有显式声明移动构造函数,当且仅当 [...]

  • X 没有用户声明的析构函数。

自从

virtual ~foo() = default;

是一个用户声明的析构函数,您不再有移动构造函数,因此它会尝试使用复制构造函数,但不能因为您有一个不可复制的成员而被删除。

要取回移动构造函数,并保持默认可构造,您需要添加

foo() = default;
foo(foo&&) = default;
foo &operator=(foo &&) = default; // add this if you want to move assign as well

foo


添加foo(foo&amp;&amp;) = default; 时必须添加foo() = default; 的原因是foo(foo&amp;&amp;) = default; 是一个使用过的声明构造函数,如果您有任何用户声明的构造函数,则不再提供默认构造函数。


这是一个“hack”,但您可以做的是将虚拟析构函数移到另一个类中,然后从该类继承。这将为您提供foo 中的虚拟析构函数,而无需声明它并为您提供所需的默认构造函数。看起来像

struct make_virtual
{
    virtual ~make_virtual() = default;
};

struct foo : make_virtual {
    std::unique_ptr<int> mem;
};

【讨论】:

  • 我一直忘记默认析构函数与默认析构函数相同。没有其他方法可以使默认析构函数为虚拟吗?
  • @JonathanMee 不。C++ 真的让你第一次就付钱(基类)。在派生类中,~derived() 将是隐式虚拟的。
  • @JonathanMee 其实我刚刚为你添加了一个“hack”。
  • @JonathanMee 您使用的是什么编译器和版本? Per this result 应被视为右值,因为它是本地自动对象。
  • @JonathanMee 那么这是否为您解答了所有问题?
【解决方案2】:

要么提供您自己的复制构造函数和默认构造函数,将成员转换为共享指针,要么提供移动构造函数。一种可能的解决方案:

struct foo {
    unique_ptr<int> mem;
    foo() = default;
    foo(const foo& copy);
    virtual ~foo() = default;
};

foo::foo(const foo& copy) : mem(new int(*copy.mem)) {}

foo make_foo() {
    foo result;
    result.mem = make_unique<int>();
    return result;
}

【讨论】:

    猜你喜欢
    • 2022-01-12
    • 2013-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-05
    • 2019-10-29
    • 1970-01-01
    相关资源
    最近更新 更多