2017-05-25 95 views
0

我已经使TestClass更好地说明了问题。 正如你所看到的,当对象被压入vector并且使用std::move函数初始化构造函数时,会调用move构造函数。 但是,当我们调用TestClass testvar2(rvalue_func());你可以看到底,该rvalue_func()的结果值分配给testvar2对象,但此举构造不叫,也没有其他的构造函数或赋值操作符被称为...C++ 11移动构造函数,使用右值通过未知方法初始化

问题: 它是如何将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

这是编译器才能进行优化,叫copy elision(这似乎是,即使它被省略掉的移动构造函数的名称)。

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

通常,编译器优化只有在一致性程序无法区分出现优化和不存在优化时(例如,将int与其他产生相同结果的算术运算结果,但CPU更便宜)。复制elision是为数不多的情况下编译器特别允许优化的方式之一。