C++拷贝构造函数初级解析:设计要点、调用机制与性能优化实践
目录
1. 拷贝构造函数的形参类型
关键要点:
2. 拷贝构造函数的调用次数分析
示例代码分析
运行结果与解析
调用次数原理
3. 减少拷贝构造次数的优化方法
优化策略
优化效果对比
总结
1. 拷贝构造函数的形参类型
关键要点:
-
必须使用引用类型
错误形式:Int(Int it)
会导致无限递归:当形参被赋值时,会再次触发拷贝构造函数调用。 -
正确形式:
const
引用
Int(const Int &it)
-
作用1:防止在拷贝过程中意外修改原对象
-
作用2:允许接受常对象(
const Int
)作为参数,避免编译错误
-
示例说明:
class Int {
public:
Int(const Int &it); // 正确写法
};
2. 拷贝构造函数的调用次数分析
示例代码分析
class Int
{
private:
int value;
public:
Int() :value() { cout << "Creat:" << value << " " << this << endl; }
Int(int x) :value(x) { cout << "Creat:" << value << " " << this << endl; }
~Int() { cout << "Destory:" << value << " " << this << endl; }
void Print() const
{
cout << "value:" << value << endl;
}
void SetValue(int x)
{
value = x;
}
Int(const Int& it)
{
value = it.value;
cout << "copy" << endl;
}
};
Int func(Int c) {
c.SetValue(100);
return c;
}
int main() {
Int a(10); // 构造a
Int b; // 默认构造b
b = func(a); // 调用func
}
运行结果与解析
Creat:10 0073FD0C // 构造a
Creat:0 0073FD00 // 构造b
copy0073FC08 // 第一次拷贝:a→形参c
copy0073FC28 // 第二次拷贝:返回值→将亡值
Destory:100 0073FC08 // 析构形参c
Destory:100 0073FC28 // 析构将亡值
Destory:100 0073FD00 // 析构b
Destory:10 0073FD0C // 析构a
调用次数原理
调用场景 | 触发原因 |
---|---|
第一次拷贝构造 | 函数调用func(a) 时,值传递形参c 需通过拷贝构造从a 创建 |
第二次拷贝构造 | 函数返回时,需通过拷贝构造创建将亡值(临时对象),用于给b 赋值 |
将亡值(expiring value):函数返回值时,若返回值类型非引用且大小超过寄存器容量,编译器会在主调函数栈帧中创建临时对象存储返回值。
3. 减少拷贝构造次数的优化方法
优化策略
-
函数形参使用引用传递
将形参改为const Int &c
,避免值传递时的拷贝构造调用。Int func(const Int &c) { // 优化后 Int tmp = c; // 仅此处触发一次拷贝构造 tmp.SetValue(100); return tmp; }
-
返回不具名对象(直接构造返回值)
通过直接返回构造的临时对象,避免中间拷贝过程。Int Add(const Int &a, const Int &b) { return Int(a.value + b.value); // 直接构造亡值,无额外拷贝 }
优化效果对比
场景 | 原调用次数 | 优化后调用次数 |
---|---|---|
调用func(a) | 2次 | 0次(形参引用) |
返回表达式直接构造对象 | 1次 | 0次(移动语义) |
总结
-
拷贝构造函数的形参必须为
const
引用-
避免无限递归和常对象传递问题
-
-
拷贝构造触发场景
-
值传递函数参数时
-
返回非引用类型对象时
-
-
优化方法
-
函数参数优先使用
const &
-
返回值时直接构造不具名对象,利用返回值优化(RVO)或移动语义(C++11+)
-
关键实践:在函数设计和返回值处理时,优先考虑引用传递和直接构造对象,可显著减少不必要的拷贝开销。