You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

拷贝构造函数何时被调用?为何我的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

疑问点

  1. 为什么A d = A(30)没有触发拷贝构造函数?
  2. A d = A(A(30))同样只输出int m constructor30,是否是编译器优化导致?
  3. 拷贝构造函数的准确调用时机是什么?

解答

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 02:27:19