C++17中删除移动赋值后,Vector类拷贝赋值未被调用的原因?
为什么拷贝赋值运算符没被调用?
先搞懂:初始化和赋值是两回事
你写的Vector u = w + r;是拷贝初始化,不是赋值操作。赋值运算符operator=只有在给已经存在的对象赋值时才会触发,比如先创建u再给它赋值:
Vector u; // 先默认构造出u u = w + r; // 这一步才会调用拷贝赋值(因为移动赋值被删了)
而初始化里的=只是语法上的写法,本质是用右边的临时对象构造新的u,和赋值半毛钱关系都没有,自然不会调用赋值运算符。
C++17的强制复制消除让拷贝构造也被跳过
就算你删了移动构造,逻辑上operator+返回的临时对象得通过拷贝构造来初始化u,但C++17标准要求编译器必须做复制消除:编译器直接在u的内存空间里构造operator+里的v3,连拷贝构造的调用都省了,所以你连Copy construction invoked.的输出都看不到。
要是想观察拷贝构造的调用,可以试试:
- 把编译标准改成C++14或更早(这时候复制消除是可选的,关了优化就能看到拷贝构造被调用)
- 或者改
operator+,让返回值没法被优化,比如:Vector operator+(const Vector& v1, const Vector& v2) { Vector v3{{1,2,13}}; Vector v4{{4,5,6}}; return rand()%2 ? v3 : v4; // 编译器没法确定返回哪个,没法做NRVO }
验证:让拷贝赋值真正被调用
把main改成这样,你就能看到拷贝赋值的输出了:
int main() { std::vector<int> q{1,2,31}; Vector w(q); Vector r(w); Vector u; // 先创建u u = w + r; // 这是真正的赋值操作,会触发拷贝赋值 return 0; }
内容的提问来源于stack exchange,提问作者Anna I
相关产品推荐
相关产品推荐

