C++拷贝构造函数调用时机
1、当用一个对象去初始化同类的另一个对象时,会引发拷贝构造函数的调用
fun f2;
fun f1 = f2;
// 注意下面不会调用拷贝构造函数(会调operator=函数),注意字眼“初始化”
fun f1, f2;
f1 = f2;
2、作为形参的对象,使用拷贝构造函数初始化
fun f1; fun f2{f1}; // 调用拷贝构造
fun f1;
fun* f2 = new fun(f1); // 调用拷贝构造
// 如果接受对象为引用,则不会调用拷贝构造函数
fun f1; // 不会调用拷贝构造函数
fun& f2{f1};
3、如果函数返回的是类的对象,那么函数返回时,类的拷贝构造函数会被调用
fun getFun() { fun f; return f; // 调用拷贝构造函数,且返回值为右值 }
// 【延伸】
fun f1;
fun&& f2 = f1.getFun(); // getFun()返回值为右值,通过右值引用"&&",将其生命周期变得和f2一样,减少内存重复开辟和释放的开销
const fun&f3 = f1.getFun(); // 也可以常量左值"const T&"来绑定,常量左值可以绑定任何值,缺点是只能读不能更改
// 【延伸】
// 如果接受类型变为引用,则不会调用拷贝构造函数
fun& getFun() // 不会调用拷贝构造函数
{
fun f;
return f;
} // 离开该代码块后会f会调用析构函数,地址虽然得到了,但是里面成员变量值都不对了
4、用花括号列表初始化一个数组中的元素或一个聚合类中的成员
fun f1; fun f2; fun f3; fun funs[] = {f1, f2, f3}; // 调用三次拷贝构造函数
5、 初始化标准库容器或者调用其insert或push成员时
fun f1; fun f2; std::vector<fun> v; v.push_back(f1); v.push_back(f2); // 若不想触发拷贝构造想触发移动构造 // 可以使用std::move(),或者emplace_back,推荐emplace_back // 前提是定义了移动构造函数 fun f1; fun f2; std::vector<fun> v; v.push_back(std>>move(f1)); v.emplace_back(f2);
扩展:
禁止拷贝构造函数调用的方法
fun(const fun&) = delete;