拷贝构造函数何时被调用?为何我的C++代码未触发拷贝构造?
关于C++拷贝构造函数调用时机与编译器优化的疑问
代码示例
#include<iostream> using namespace std; class A{ private: int x; public: A(){x=10;} A(int m){x=m; cout << "int m constructor" << m << endl;} A(A& a){cout << "copy constructor:" << a.x << endl; x=a.x;} A(A&& a){cout << "move constructor:" << a.x << endl; x=a.x;} }; int main(){ A a(100); A b = a; A d = A(30); }
实际输出
int m constructor100 copy constructor:100 int m constructor30
预期输出
int m constructor100 copy constructor:100 copy constructor:30
疑问点
- 为什么
A d = A(30)没有触发拷贝构造函数? A d = A(A(30))同样只输出int m constructor30,是否是编译器优化导致?- 拷贝构造函数的准确调用时机是什么?
解答
1. 编译器优化:返回值优化(RVO)
你遇到的现象是C++标准允许的返回值优化(Return Value Optimization, RVO),更具体是临时对象消除。编译器可以直接在目标对象d的内存位置构造临时对象A(30),完全省略拷贝/移动构造函数的调用。
对于A d = A(30),编译器会将其优化为直接调用A(int)构造函数初始化d,等价于A d(30),因此不会触发拷贝或移动构造。同理,A d = A(A(30))这种嵌套的临时对象构造,编译器会直接跳过中间临时对象,直接在d的位置构造最终对象,同样省略所有拷贝/移动操作。
如果想要观察未优化的行为,可以使用编译器选项禁用优化,比如GCC/Clang的-fno-elide-constructors。此时A d = A(30)会触发移动构造函数(而非拷贝构造),因为A(30)是右值,无法绑定到你的拷贝构造函数的非const左值引用A&,但可以绑定到移动构造的右值引用A&&。
2. 拷贝构造函数的准确调用时机
拷贝构造函数通常定义为A(const A&),你的代码中是A(A&),会限制其使用场景,会在以下场景被调用:
- 拷贝初始化:用一个已存在的左值对象初始化新对象时,比如
A b = a;(你的代码中这行触发了拷贝构造)。 - 值传递函数参数:当函数参数是按值传递的同类型对象时,比如
void func(A obj),调用func(a)会触发拷贝构造。 - 值返回对象:当函数按值返回同类型对象时,若未被编译器优化,会触发拷贝构造。
- 显式复制对象:比如调用
A c(a);或者A c = static_cast<A>(a);。 - 容器操作:当向容器(如
std::vector)中插入/拷贝元素时,若涉及值拷贝,会触发拷贝构造。
注意:如果拷贝构造函数参数是A&(非const),它无法接收临时对象(右值),只有const A&的拷贝构造才能同时接收左值和右值(在没有移动构造的情况下)。
内容的提问来源于stack exchange,提问作者A J
相关产品推荐
相关产品推荐

