你能在函数调用中直接使用 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);
几乎总是错误的。
我正在尝试更新一些传递新对象的代码。目标是用智能指针来管理它。煮沸后,它看起来很像:
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-constructsm_mystring
通常,带有名称的变量不会隐式地从中移动。
如果您从函数中按值返回局部变量,该对象可能会在 so-called Named Return Value Optimization 中自动移动。这为按值返回提供了很好的速度提升。在实践中你不需要考虑太多这一点,只要注意
return std::move(whatever);
几乎总是错误的。