我正在尝试更新一些传递新对象的代码。目标是使用智能指针对其进行管理。熬下来,看起来很像这样:
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似乎都不介意。在开始对性能更为关键的其他地方进行类似更改之前,我希望有一个准确的了解。
答案 0 :(得分:0)
简短答案:是
函数调用std::make_unique<Z>()
返回一个右值,因此,如果将其直接传递到另一个函数中,则无需将其包装在std::move()
中。
答案 1 :(得分:0)
我的问题是,第一个std :: move()(在make_unique附近)是否必要?
如果您指的是这一行:
X() : yptr(Y::create( std::move( std::make_unique<Z>(Z()) ) )){}
然后不,因为std::make_unique<Z>
返回已经是prvalue
的临时值,所以完全没有必要。您可以执行以下操作:
auto ptr = std::move( std::move( std::move( std::make_unique<Z>() ) ) );
代替
auto ptr = std::make_unique<Z>();
但是所有moves
都是不必要的,事实已经清楚地表明了这一点。
答案 2 :(得分:0)
是的!无需make_unique
左右移动。
std::move
用于将左值引用&
(指向现有对象)转换为右值引用&&
(表示临时值,或可以从中移出。)
如果您将unique_ptr
分配给命名变量,那么如果您想转移其所有权,则确实需要从其std::move
(通常;请参见下文)。您不能直接将r值引用绑定到变量。
由表达式或函数调用返回的值(例如unique_ptr
返回的make_shared
)是临时的,因此它自然可以绑定到r值表达式并从中移出隐式地。
请注意,在某些特殊情况下,您不需要使用std::move
:
如果您有一个命名变量,其类型是一个r值引用,则要做,需要std::move
,以避免通过复制传递它:
MyClass(std::string&& s) : m_mystring(s) {}
复制-构造m_mystring
MyClass(std::string&& s) : m_mystring(std::move(s)) {}
移动结构m_mystring
通常,带名称的变量不会隐式地移出。
如果要通过函数从值返回局部变量,则该对象可能会自动从所谓的Named Return Value Optimization中移出。这样可以很好地提高按值返回的速度。在实践中,您无需考虑这一点,只需注意return std::move(whatever);
几乎总是错误的。