C++创建A类对象时为何调用xINT的拷贝构造函数?
问题分析:A类对象创建时xINT拷贝构造与赋值运算符被调用的原因
首先看你提供的代码:
class xINT { private: int num; static int countCtor; static int countDtor; static int countCopycon; static int countOpAssign; public: xINT() { std::cout << this << ": " << "ctor" << std::endl; ++countCtor; } ~xINT() { std::cout << this << ": " << "dtor" << std::endl; ++countDtor; } xINT(const xINT& x) { std::cout << this << ": " << "copycon of " << std::dec << &x << std::endl; num = x.getNum(); ++countCopycon; } xINT& operator=(const xINT& x) { if (&x == this) { std::cout << "op=" << std::endl; //return *this; } std::cout << this << ": " << "op= of " << std::dec << &x << std::endl; num = x.getNum(); ++countOpAssign; return *this; } int getNum() const { return num; } void setNum(int val) { num = val; } static void statistik(std::ostream&); static void reset(); }; class A { public: A(xINT i) { i_ = i; } private: xINT i_; }; int main() { xINT i; cout << &i << endl; i.setNum(42); { std::cout << "Class A:" << std::endl; A a(i); } }
调试时发现执行A a(i);创建A类对象时,程序先进入xINT的拷贝构造函数,之后还会调用xINT的赋值运算符重载,以下是具体原因和特殊成员函数的调用场景:
现象原因
问题出在A类的构造函数实现上:
A(xINT i) { i_ = i; }
执行A a(i);时,会依次发生三个关键操作:
- 形参传递触发拷贝构造:A的构造函数参数是值传递(
xINT i),所以main中的i会被拷贝一份作为构造函数的形参,这一步调用xINT的拷贝构造函数。 - 成员变量默认构造:进入构造函数体之前,A的成员
i_会被自动默认构造(因为构造函数没有用初始化列表显式初始化它),这一步会调用xINT的无参构造函数(你可以从输出的ctor日志看到这一步)。 - 赋值运算符被触发:构造函数体里的
i_ = i;是给已经存在的i_对象赋值,所以会调用xINT的赋值运算符重载。
这就是你看到两次特殊成员函数调用的根本原因。
优化建议(可选)
如果想避免多余的默认构造+赋值操作,改用初始化列表直接初始化成员变量,这样能把步骤2和3合并成一次拷贝构造:
// 用初始化列表直接拷贝构造i_ A(xINT i) : i_(i) {}
进一步可以把参数改成const引用,避免形参的拷贝操作,提升效率:
// 形参用const引用减少一次拷贝 A(const xINT& i) : i_(i) {}
这样整个过程只会触发一次拷贝构造,没有多余的赋值操作。
特殊成员函数的调用场景
拷贝构造函数
- 用已存在的对象初始化新对象:比如
xINT a = b;、xINT a(b); - 函数参数按值传递:比如定义
void func(xINT val),调用func(b)时会触发拷贝构造 - 函数按值返回对象:某些情况下编译器会优化掉,但标准允许这种场景下调用拷贝构造
赋值运算符重载
- 给已存在的对象赋值另一个对象:比如
a = b;,这里a必须是已经完成构造的对象 - 核心区别:拷贝构造是创建新对象,赋值是修改已有对象的状态,这是两者最关键的不同点
内容的提问来源于stack exchange,提问作者AZYZ
相关产品推荐
相关产品推荐

