C++ 11:未触发移动构造函数

see*_*uch 1 c++ constructor move-constructor move-semantics c++11

最近我一直在研究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();
}
Run Code Online (Sandbox Code Playgroud)

(I引用的一些代码从1)

代码可能看起来很长,但它实际上非常天真,只是一个转储数组.

在第67行,我特意创建了一个带有右值的b,并期望看到如何调用移动构造函数.但令人失望的是,该计划的产出是:

Constructor: 0x7fff51d60be0
Temp ArrayWrapper created!
This address: 0x7fff51d60be0
Destructor: 0x7fff51d60be0
Run Code Online (Sandbox Code Playgroud)

打印的三个地址是相同的,并且根本不调用移动构造函数!事实上,我后来试图删除移动构造函数,程序仍然编译并给出相同的输出!如果你仔细一点,你会发现构造函数只在构造一个时被调用一次.也就是说,当构造b时,根本不会调用任何构造函数,既不移动也不复制!

我真的很困惑.任何人都可以告诉我为什么移动构造函数没有被触发,以及地球b是如何构建的?

Yak*_*ont 6

你正在经历的是复制省略 - 复制和移动构造函数可以在某些上下文中跳过,即使跳过它们会产生可观察到的副作用.常见情况包括RVO和NRVO(返回值优化和命名RVO)或匿名临时的复制初始化.

要阻止它,显式调用std::move从函数返回的点,以及构造值的位置main,因为std::move's rvalue cast使得elision非法. std::move取一个T&或者T&&将它变成一个T&&防止"左手侧"执行省略的方式,因为省略(至少在这一点上)某些狭窄的情况.

阻止省略通常是一个坏主意,但std::move会做到这一点.


Gre*_*ape 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();
}
Run Code Online (Sandbox Code Playgroud)

并关闭优化.