【问题标题】:unique_ptr swap doesn't workunique_ptr 交换不起作用
【发布时间】:2018-06-25 08:53:36
【问题描述】:

我的代码是:

#include <memory>
#include <vector>

struct Core{
    Core(int n){} };

int main() {
    int base;
    std::vector<std::unique_ptr<Core>> cores;

    cores.push_back( std::move(std::unique_ptr<Core>(new Core(base))) );
    cores[0].swap(std::unique_ptr<Core>(new Core(base)));

    return 0;
}

我得到这个错误:

||=== 构建:在测试中发布(编译器:GNU GCC 编译器)===|

函数“int main()”错误:没有匹配函数调用“std::unique_ptr::swap(std::unique_ptr)”

注意:候选人是:

注意: void std::unique_ptr<_tp>::swap(std::unique_ptr<_tp>&) [with_Tp = Core; _Dp = std::default_delete]

注意:没有已知的参数 1 从 'std::unique_ptr' 到 'std::unique_ptr&' 的转换

【问题讨论】:

  • 仅供参考:由于访问未初始化的int base,您的代码具有未定义的行为。此外,执行std::move
  • 你为什么要换成临时的? unique_ptr::swap 的签名不允许这样做。
  • 我想改变我的vector[0]里面的内容,但我不知道怎么做,我想用一个交换,让临时死在作用域的末尾跨度>
  • 我的 gcc 版本对用户更友好:invalid initialization of non-const reference of type ‘std::unique_ptr&lt;Core&gt;&amp;’ from an rvalue of type ‘std::unique_ptr&lt;Core&gt;’

标签: c++ c++11 swap unique-ptr


【解决方案1】:

您需要一个左值 std::unique_ptr&lt;Core&gt; 来交换,不允许使用未命名的临时值。

你能做的是

cores.push_back(std::unique_ptr<Core>(new Core(base))); // don't need move here
{
    std::unique_ptr<Core> other(new Core(base));
    cores[0].swap(other);
}

【讨论】:

  • 还有另一种更有效的方法来更改我的矢量元素之一的内容吗?我正在使用交换作为替代方案,但它真的很好吗?
  • 这使用了与vector&lt;...&gt;::push_back 相同的重载。 move 什么都不做
【解决方案2】:

你使用std::move 太多了。在您的情况下,移动会自动发生。所以,你可以写

cores.push_back( std::unique_ptr<Core>(new Core(base)) );
cores[0] = std::unique_ptr<Core>(new Core(base));

或者,使用std::make_uniquestd::unique_ptr::reset

cores.push_back( std::make_unique<Core>(base) );
cores[0].reset(new Core(base));

但是,如果您将 unique_ptr 作为局部变量,则必须使用 std::move

std::unique_ptr<Core> p(new Core(base));
cores.push_back(std::move(p));

这和上面一样有效,但是会创建一个潜在的不必要的局部变量。

【讨论】:

    【解决方案3】:

    您不能像这样与临时对象(rvalue)交换:

    cores[0].swap(std::unique_ptr<Core>(new Core(base))); // error
    

    但是临时对象可以像这样与命名对象 (lvalue) 交换

    std::unique_ptr<Core>(new Core(base)).swap(cores[0]); // but this works
    

    您也可以直接设置值:

    cores[0] = std::unique_ptr<Core>(new Core(base));
    

    或者(更好)使用std::make_unique

    cores[0] = std::make_unique<Core>(base);
    

    您将对象构造函数的参数直接传递给std::make_unique 函数。

    如果你必须使用new,那么总是有std::unique_ptr::reset函数:

    cores[0].reset(new Core(base));
    

    【讨论】:

    • 第二个代码片段是正确/最简单的交换方式的明显答案。恕我直言,这应该被接受。此外,每个人都简化了他的 push_back 语句,这不是问题的一部分,但没有提到更简单的 emplace_back(new Core(base));
    • @lars emplace_back(new Core(base)) 泄漏,以防矢量调整大小抛出。
    • 如果我尝试分配核心[0],我会得到这个error: use of deleted function 'std::unique_ptr&lt;_Tp, _Dp&gt;&amp; std::unique_ptr&lt;_Tp, _Dp&gt;::operator=(const std::unique_ptr&lt;_Tp, _Dp&gt;&amp;) [with _Tp = Core; _Dp = std::default_delete&lt;Core&gt;]'|
    • @Sheed 你做的和我在这里做的一样吗?您只能分配这样的临时对象,而不是命名对象。如果要分配命名对象,则必须使用std::move()
    猜你喜欢
    • 2013-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-19
    • 2012-08-20
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    相关资源
    最近更新 更多