gpt4 book ai didi

c++ - 为什么需要 std::move?

转载 作者:可可西里 更新时间:2023-11-01 14:57:03 26 4
gpt4 key购买 nike

我读了一个beautiful article 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;
};

很明显,在上面的移动构造函数实现中,嵌入元素 _metadata 不会发生移动。为了促进这一点,技巧是像这样使用 std::move() 方法。

ArrayWrapper (ArrayWrapper&& other) 
: _p_vals( other._p_vals )
, _metadata( std::move( other._metadata ) )
{
other._p_vals = NULL;
}

到目前为止,还不错。

标准说:

§5(C++11 §5[expr]/6):

[ Note: An expression is an xvalue if it is:

  • the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type,

  • a cast to an rvalue reference to object type,

  • a class member access expression designating a non-static data member of non-reference type in which the object expression is an xvalue, or

  • a .* pointer-to-member expression in which the first operand is an xvalue and the second operand is a pointer to data member.

我的问题:

现在,移动构造函数中的变量 other 是一个 xvalue(我说的对吗?)。然后根据上面的最后一条规则,other._metadata 也应该是一个 xvalue。因此,编译器可以隐含地使用 _metadata 类的移动构造函数。所以,这里不需要std::move

我错过了什么?

最佳答案

您的假设并不正确。构造函数的参数是一个xvalue,它允许绑定(bind)右值引用,但是一旦右值引用被绑定(bind),在构造函数内部,它就不再是一个xvalue 而是一个左值。从概念上讲,调用位置的对象即将到期,但在构造函数内部并且在完成之前它不再到期,因为稍后可以在构造函数 block 中使用它。

ArrayWrapper f();
ArrayWrapper r = f(); // [1]

在 [1] 中,表达式 f() 指的是一个临时变量,它将在调用构造函数后过期,因此它可以被一个右值绑定(bind)-引用。

ArrayWrapper (ArrayWrapper&& other) 
: _p_vals( other._p_vals )
, _metadata( other._metadata ) // [2]
{
other._p_vals = NULL;
std::cout << other._metadata << "\n"; // [3]
}

在构造函数中,other 不会过期,它对于构造函数的每条指令都是有效的。如果编译器允许在 [2] 中移动,那么进一步使用 [3] 中的变量将是无效的。您必须明确告诉编译器您希望该值现在过期。

关于c++ - 为什么需要 std::move?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11724592/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com