c ++ 11移动构造函数,使用rvalue通过未知方法初始化

时间:2017-05-25 17:12:58

标签: c++11 rvalue move-constructor

我已经做了TestClass来更好地说明问题。 如您所见,当对象被推入向量时以及使用std::move函数初始化构造函数时,将调用移动构造函数。 但是当我们调用TestClass testvar2(rvalue_func());时你可以看到rvalue_func()的结果值被分配给testvar2对象,但是没有调用move构造函数,也没有其他构造函数或称任务操作员......

问题: 如何在不调用任何内容的情况下将值从rvalue_func()复制到testvar2以及为什么不调用移动构造函数?

#include <iostream>
using std::cout;
using std::endl;

#include <vector>

class TestClass {
public:

    TestClass(int arg_x=0, int arg_y=0) :
            values { nullptr } {

        values = new int[2];
        values[0] = arg_x;
        values[1] = arg_y;
        cout << "default constructor " << "x = " << values[0] << " y = "
                << values[1] << endl;
    }

    TestClass(const TestClass &arg) :
            values { nullptr } {

        values = new int[2];

        values[0] = arg.values[0];
        values[1] = arg.values[1];

        cout << "copy constructor " << "x = " << values[0] << " y = "
                << values[1] << endl;
    }

    TestClass(TestClass &&arg) :
            values { arg.values } {
        arg.values = nullptr;
        cout << "move constructor " << "x = " << values[0] << " y = "
                << values[1] << endl;
    }

    TestClass &operator=(TestClass &right) {
        cout << "assignment operator =" << endl;
        if (this != &right) {
            delete values;
            values = nullptr;
            values = new int[2];
            values[0] = right.values[0];
            values[1] = right.values[2];
        }
        return *this;
    }

    TestClass &operator=(TestClass &&right) {
        cout << "move assignment operator =" << endl;
        if (this != &right) {
            delete values;
            values = right.values;
            right.values = nullptr;
        }
        return *this;
    }

    void print() {
        if (values != nullptr)
            cout << "x = " << values[0] << " y = " << values[1] << endl;
    }
private:
    int *values;
};

TestClass rvalue_func() {
    cout << "creating TestClass temp" << endl;
    TestClass temp(100, 200);
    cout << "TestClass temp is created" << endl;
    return temp;
}
void test_rvalues() {
    cout << "-------------vector push back--------------" << endl;
    std::vector<TestClass> test_vector;
    test_vector.push_back(TestClass(1, 2));

    cout << "-----rvalue constructor with std::move-----" << endl;
    TestClass testvar1(std::move(rvalue_func()));

    cout << "------------rvalue constructor-------------" << endl;
    TestClass testvar2(rvalue_func());


    cout << "-------------------------------------------" << endl;
    cout << "testvar2 values ";
    testvar2.print();
}

int main(int argc, char *argv[]) {
    test_rvalues();

    return 0;
}

结果:

-------------vector push back--------------
default constructor x = 1 y = 2
move constructor x = 1 y = 2
-----rvalue constructor with std::move-----
creating TestClass temp
default constructor x = 100 y = 200
TestClass temp is created
move constructor x = 100 y = 200
------------rvalue constructor-------------
creating TestClass temp
default constructor x = 100 y = 200
TestClass temp is created
-------------------------------------------
testvar2 values x = 100 y = 200

1 个答案:

答案 0 :(得分:1)

这是允许编译器执行的优化,称为copy elision(这似乎是名称,即使它是被删除的移动构造函数)。

基本上,有时允许编译器(或者,因为C ++ 17,甚至是必需的)不调用副本或移动构造函数,如果相反它只能在它将被复制或移动到的位置创建对象。在这种情况下,它知道对象会进入testvar2,所以它只是在那里创建了对象。

通常只要符合程序无法区分优化存在与不存在之间的区别(例如,将int上的算术运算替换为其他的算法操作),就允许编译器优化。产生相同的结果,但CPU计算成本更低)。复制省略是少数几种情况之一,特别允许编译器以一种可以区分的方式进行优化。