C 11:没有触发移动构造器

C++11: Move constructor is not triggered

本文关键字:移动 构造器      更新时间:2023-10-16

最近我一直在研究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

打印的三个地址是相同的,并且根本不调用移动构造函数!实际上,我后来尝试删除MOVE构造函数,并且该程序仍然进行了编译,并给出了相同的输出!而且,如果您仔细看一看,您会发现构造函数仅在构造时调用一次。也就是说,当b构造b时,根本没有构造函数,也没有移动或复制!

我真的很困惑。谁能告诉我为什么没有触发移动构造函数,以及如何构建地球b?

这是因为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();
}

并关闭优化。

您所经历的被称为复制elision-复制和移动构造函数可以在某些情况下跳过,即使跳过它们会具有可观察到的副作用。常见案例包括RVO和NRVO(返回值优化和命名RVO)或来自匿名临时性的复制限制。

阻止它,在您从函数返回的点上明确调用std::move,以及在main中构造值的位置,因为std::move的rvalue cast cast cast cast cons cons cons cast cast cast cast cast cast casts cons cast cast cast cons cons cons cast conts cons cost cast cost cast conts cons cost cast contssion的rvalue cast cast cast cast cast cast cast cast cast cast的。std::move采用T&T&&,并以防止"左手侧"执行力流的方式将其转变为T&&,因为(至少在此时)将ELISION限制为某些窄情况。

> 。

通常是一个坏主意,但是std::move会做到。