Hec*_*tor 5 c++ move-semantics c++11
我一直在尝试编写一个不能复制但可以移动的类,除非使用命名构造函数,否则不能创建该类。我实现了namedConstructor3以下目标。但是,我不明白为什么namedConstructor2失败了。
struct A
{
int a;
//static A && namedConstructor1( int a_A )
//{
// A d_A( a_A );
// return d_A; // cannot convert from A to A&&
//}
static A && namedConstructor2( int a_A )
{
wcout << L"Named constructor 2\n";
A d_A( a_A );
return move( d_A );
}
static A namedConstructor3( int a_A )
{
wcout << L"Named constructor 3\n";
A d_A( a_A );
return move( d_A );
}
A( A && a_RHS ) : a( a_RHS.a )
{
a_RHS.a = 0;
wcout << L"\tMoved: a = " << a << endl;
}
~A()
{
wcout << L"\tObliterated: a = " << a << endl;
a = -a;
}
A( const A & ) = delete;
A & operator =( const A & ) = delete;
protected:
A( int a_A = 0 ) : a( a_A )
{
wcout << L"\tCreated: a = " << a << endl;
}
};
int main()
{
A d_A2 = A::namedConstructor2( 2 );
A d_A3 = A::namedConstructor3( 3 );
wcout << "Going out of scope\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是
Named constructor 2
Created: a = 2
Obliterated: a = 2
Moved: a = -2
Named constructor 3
Created: a = 3
Moved: a = 3
Obliterated: a = 0
Going out of scope
Obliterated: a = 3
Obliterated: a = -2
Run Code Online (Sandbox Code Playgroud)
问题:
namedConstructor2如输出的第三行和第四行所证明的,为什么析构函数在move构造函数之前被调用?
为什么销毁的数据仍可用于移动的构造函数(如输出的第4行所示)?
“不是namedConstructor2更自然”,而不是namedConstructor3从的签名std::move使我认为的返回值std::move具有“两个&&”的意义上说?
????
template< class T >
typename std::remove_reference<T>::type&& move( T&& t )
Run Code Online (Sandbox Code Playgroud)
与VS2013u4一起编译。
编辑
重复数据删除器的答案使我满意。此编辑是出于完整性考虑。答案和评论建议namedConstructor3是“次优”的。我加了
static A namedConstructor4( int a_A )
{
wcout << L"Named constructor 4\n";
A d_A( a_A );
return d_A;
}
Run Code Online (Sandbox Code Playgroud)
在类A d_A4 = A::namedConstructor4( 4 );的main功能。新的输出(在发布模式下而不是在调试模式下编译时)显示最佳情况甚至不会移动对象:
Named constructor 2
Created: a = 2
Obliterated: a = 2
Moved: a = -2
Named constructor 3
Created: a = 3
Moved: a = 3
Obliterated: a = 0
Named constructor 4
Created: a = 4
Going out of scope
Obliterated: a = 4
Obliterated: a = 3
Obliterated: a = -2
Run Code Online (Sandbox Code Playgroud)
std::move(lvalue or xvalue)不调用析构函数。
它只是将传递的引用更改为右值引用,因此移动语义适用。
那么,为什么你的本地被毁得太早了呢?
简单,返回对局部变量的引用就是UB:
局部变量的内存可以在其作用域之外访问吗?
逐一检查您的命名构造函数:
namedConstructor1返回右值引用。namedConstructor2原则上与 相同namedConstructor1,但您添加了从左值到右值引用的显式转换(以 的形式std::move),这会关闭编译器。namedConstructor3还可以,虽然不是最理想的。std::move禁用返回值优化,这将消除在这种情况下实际移动(或复制)实现的需要。