最近我一直在研究C ++ 11中的移动语义。我印象非常深刻,以至于我迫不及待地试着把它弄脏了。以下是我的代码:
#include <iostream>
using namespace std;
class ArrayWrapper
{
public:
// default constructor produces a moderately sized array
ArrayWrapper ()
: _p_vals( new int[ 64 ] )
, _size( 64 )
{
cout << "Default constructor: " << this << endl;
}
explicit ArrayWrapper (int n)
: _p_vals( new int[ n ] )
, _size( n )
{
cout << "Constructor: " << this << endl;
}
// move constructor
ArrayWrapper (ArrayWrapper&& other)
: _p_vals( other._p_vals )
, _size( other._size )
{
cout << "Move constructor: " << this << endl;
other._p_vals = NULL;
other._size = 0;
}
// copy constructor
ArrayWrapper (const ArrayWrapper& other)
: _p_vals( new int[ other._size ] )
, _size( other._size )
{
cout << "Copy constructor: " << this << endl;
for ( int i = 0; i < _size; ++i )
{
_p_vals[ i ] = other._p_vals[ i ];
}
}
~ArrayWrapper ()
{
cout << "Destructor: " << this << endl;
delete [] _p_vals;
}
void self () {
cout << "This address: " << this << endl;
}
public:
int *_p_vals;
int _size;
};
ArrayWrapper two() {
ArrayWrapper a(7);
cout << "Temp ArrayWrapper created!" << endl;
return a;
}
int main() {
ArrayWrapper b (two());
b.self();
}
(我引用了1中的一些代码)
代码可能看起来很长,但它实际上非常天真,只是一个转储数组。
在第67行,我故意创建了一个带有右值的b,并期望看到如何调用移动构造函数。但令人失望的是,该计划的结果是:
Constructor: 0x7fff51d60be0
Temp ArrayWrapper created!
This address: 0x7fff51d60be0
Destructor: 0x7fff51d60be0
打印的三个地址是相同的,并且根本不调用移动构造函数! 事实上,我后来试图删除移动构造函数,程序仍然编译并给出相同的输出!如果你仔细一点,你会发现构造函数只在构造一个时被调用一次。也就是说,当构造b时,根本不会调用构造函数,既不移动也不复制!
我真的很困惑。谁能告诉我为什么移动构造函数没有被触发,以及地球b是如何构建的?
答案 0 :(得分:6)
您所经历的内容被称为复制省略 - 在某些情况下可以跳过复制和移动构造函数,即使跳过它们会产生可观察到的副作用。常见情况包括RVO和NRVO(返回值优化和命名RVO)或匿名临时的复制初始化。
要阻止它,请在您从函数返回的位置显式调用std::move
,并在main
中构建值,作为std::move
的右值投射使elision非法。 std::move
获取T&
或T&&
并将其转换为T&&
,以防止&#34;左侧&#34;因为精算受到限制(至少在这一点上)到某些狭隘的案件。
阻止省略通常是一个坏主意,但std::move
会这样做。
答案 1 :(得分:5)
这是因为RVO(返回值优化)技巧。
ArrayWrapper two();
中的对象是代替ArrayWrapper b;
而创建的。
这就是为什么只有一个建筑+破坏。
尝试将其修改为:
ArrayWrapper two(bool disable_rvo) {
ArrayWrapper a(7);
cout << "Temp ArrayWrapper created!" << endl;
if (disable_rvo)
return a;
else
return ArrayWrapper(8);
}
int main() {
ArrayWrapper b (two(true));
b.self();
}
关闭优化。