你能在函数调用中直接使用 make_unique 吗?

Can you use make_unique directly in a function call?

我正在尝试更新一些传递新对象的代码。目标是用智能指针来管理它。煮沸后,它看起来很像:

class X
{
    shared_ptr<Y> yptr;

    X() : yptr(Y::create(new Z())){}
};

class Y
{
    Z* zptr;
    static shared_ptr<Y> create(Z* zp)
    {
        if(!zp) return nullptr;
        else return shared_ptr<Y>(new Y(zp));
    }

    Y(Z* zp) : zptr(zp){}
}

到目前为止这似乎有效:

class X
{
    shared_ptr<Y> yptr;

    X() : yptr(Y::create(  std::move(  std::make_unique<Z>(Z())  )  )){}
};

class Y
{
    unique_ptr<Z> zptr;
    static shared_ptr<Y> create(unique_ptr<Z> zp)
    {
        if(!zp) return nullptr;
        else return shared_ptr<Y>(new Y(std::move(zp)));
    }

    Y(unique_ptr<Z> zp) : zptr(std::move(zp)){}
}

我的问题是,第一个 std::move()(大约 make_unique)是否必要? Visual Studio 似乎不介意任何一种方式。在开始对性能更为关键的其他地方进行类似更改之前,我宁愿有一个准确的了解。

简答:

函数调用 std::make_unique<Z>() returns 一个右值,因此如果您将它直接传递给另一个函数,则无需将其包装在 std::move() 中。

My question is, is the first std::move() (around make_unique) necessary?

如果你指的是这一行:

X() : yptr(Y::create(  std::move(  std::make_unique<Z>(Z())  )  )){}

那么不,完全没有必要,因为 std::make_unique<Z> returns 已经是临时的 prvalue。你可以这样做:

auto ptr = std::move( std::move( std::move( std::make_unique<Z>() ) ) );

而不是

auto ptr = std::make_unique<Z>();

但所有这些 moves 都是不必要的,编译的事实清楚地表明了这一点。

是的! make_unique 的移动是不必要的。

std::move 存在将 l-value 引用 &(引用现有对象)转换为 r-value 引用 &&(表示临时值,或可以移动的东西)。

如果您将 unique_ptr 分配给命名变量,那么如果您想要转移其所有权(通常;见下文),您确​​实需要从它 std::move 。您不能直接将 r-value 引用绑定到变量。

表达式或函数调用返回的值,例如 make_shared 返回的 unique_ptr,是一个临时值,因此它自然可以绑定到 r-value 表达式和隐式 moved-from。

请注意,在某些特殊情况下您需要使用和不需要使用 std::move:

  • 如果你有一个命名变量,其类型是 r-value 引用,你 do 需要 std::move 它以避免传递复制:

    MyClass(std::string&& s) : m_mystring(s) {} 复制-构造m_mystring

    MyClass(std::string&& s) : m_mystring(std::move(s)) {} move-constructs m_mystring

    通常,带有名称的变量不会隐式地从中移动。

  • 如果您从函数中按值返回局部变量,该对象可能会在 so-called Named Return Value Optimization 中自动移动。这为按值返回提供了很好的速度提升。在实践中你不需要考虑太多这一点,只要注意 return std::move(whatever); 几乎总是错误的。