我在C++ 11中阅读了一篇关于移动语义的精彩文章.本文以非常直观的方式编写.下面给出了本文中的示例类.
class ArrayWrapper
{
public:
// default constructor produces a moderately sized array
ArrayWrapper ()
: _p_vals( new int[ 64 ] )
, _metadata( 64, "ArrayWrapper" )
{}
ArrayWrapper (int n)
: _p_vals( new int[ n ] )
, _metadata( n, "ArrayWrapper" )
{}
// move constructor
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _metadata( other._metadata )
{
other._p_vals = NULL;
}
// copy constructor
ArrayWrapper (const ArrayWrapper& other)
: _p_vals( new int[ other._metadata.getSize() ] )
, _metadata( other._metadata )
{
for ( int i = 0; i < _metadata.getSize(); ++i )
{
_p_vals[ i ] = other._p_vals[ i ];
}
}
~ArrayWrapper ()
{
delete [] _p_vals;
}
private:
int *_p_vals;
MetaData _metadata;
};
Run Code Online (Sandbox Code Playgroud)
显然,在上面的移动构造函数实现中,嵌入元素不会发生移动_metadata.为了方便这一点,诀窍是使用这样的std::move()方法.
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _metadata( std::move( other._metadata ) )
{
other._p_vals = NULL;
}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.
标准说:
§5(C++11§5[expr]/6):
[注意:表达式是xvalue,如果它是:
调用函数的结果,无论是隐式还是显式,其返回类型是对象类型的右值引用,
强制转换为对象类型的右值引用,
一个类成员访问表达式,指定非引用类型的非静态数据成员,其中对象表达式是xvalue,或者
一个
.*指针到构件表达,其中第一操作数是一个x值和第二个操作数是一个指向数据成员.
我的问题:
现在,other移动构造函数中的变量是一个xvalue(我是对的吗?).然后根据上面的最后一条规则,other._metadata也应该是一个xvalue.因此编译器可以隐含地使用类的移动构造函数_metadata.所以,不需要在std::move这里.
我错过了什么?
Dav*_*eas 15
你的假设不是真的.构造函数的参数是一个xvalue,它允许绑定rvalue-reference,但是一旦绑定了rvalue-reference,在构造函数中,它就不再是一个xvalue而是一个lvalue.从概念上讲,调用位置的对象即将到期,但在构造函数内部直到完成它不再过期,因为它可以在构造函数块中稍后使用.
ArrayWrapper f();
ArrayWrapper r = f(); // [1]
Run Code Online (Sandbox Code Playgroud)
在[1]中,表达式f()引用一个临时的,它将在调用构造函数后到期,因此它可以被一个rvalue-reference绑定.
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _metadata( other._metadata ) // [2]
{
other._p_vals = NULL;
std::cout << other._metadata << "\n"; // [3]
}
Run Code Online (Sandbox Code Playgroud)
在构造函数内部,other没有到期,它将对构造函数的每个指令都是活动的.如果编译器允许在[2]中移动,则可能在[3]中进一步使用该变量将无效.您必须明确告诉编译器您希望该值现在到期.
| 归档时间: |
|
| 查看次数: |
543 次 |
| 最近记录: |