我已经做了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
答案 0 :(得分:1)
这是允许编译器执行的优化,称为copy elision(这似乎是名称,即使它是被删除的移动构造函数)。
基本上,有时允许编译器(或者,因为C ++ 17,甚至是必需的)不调用副本或移动构造函数,如果相反它只能在它将被复制或移动到的位置创建对象。在这种情况下,它知道对象会进入testvar2
,所以它只是在那里创建了对象。
通常只要符合程序无法区分优化存在与不存在之间的区别(例如,将int
上的算术运算替换为其他的算法操作),就允许编译器优化。产生相同的结果,但CPU计算成本更低)。复制省略是少数几种情况之一,特别允许编译器以一种可以区分的方式进行优化。