C++中的拷贝、赋值和销毁

本文探讨了拷贝构造函数和拷贝赋值运算符等关键概念,区分了拷贝初始化与直接初始化的过程,并详细解释了如何通过拷贝构造函数完成拷贝初始化。

几个重要的概念:拷贝构造函数、拷贝赋值运算符;拷贝初始化、直接初始化


如图,出现了两次“拷贝构造函数”。

直接调用构造函数(包括拷贝构造函数)来初始化对象的都是直接初始化。

用赋值运算符、函数的传值调用、函数返回非引用对象、用花括号列表进行初始化以及标准库容器的insert和push_back都是拷贝初始化。

拷贝初始化通常使用拷贝构造函数来完成。

<think>嗯,用户的问题是关于C++类的默认拷贝构造函数赋值运算符重载析构函数的详细介绍。看起来用户正在深入学习C++的类设计基础,可能是在准备面试或者开发中遇到了相关需求。 用户提供的引用信息很有价值,特别是三/五法则的概念析构函数特性。我需要整合这些资料,同时补充一些关键点: 关于默认拷贝构造函数,准备强调浅拷贝行为可能带来的指针问题,这是很多初学者容易踩的坑。需要解释编译器生成的版本会逐一拷贝成员变量,但遇到指针时只会复制地址而非内容,这就是为什么需要自定义拷贝控制函数。 对于默认赋值运算符,考虑要说明与拷贝构造的区别在于对象已存在,要特别注意自赋值检查资源释放的顺序。引用资料中提到应返回左侧对象的引用,这点很重要,要结合运算符重载规范解释。 析构函数部分,用户已引用"堆上对象不手动释放会造成内存泄漏"的要点,准备用图示代码示例强化这个关键概念。考虑说明默认析构函数对基本类型有效但无法释放动态资源。 准备回答时组织三部分独立介绍每个函数,之后用对比表格总结特性。在安全警告部分规划列出具体的风险场景:包含指针成员的类、管理文件句柄或网络连接的类等。考虑通过双重删除的实际代码演示崩溃原理,增强说明。 最后补足五法则的现代C++实践部分:当声明任何拷贝控制函数时,建议显式定义全部五个,避免编译器生成不正确版本。考虑提到移动语义对资源管理效率的提升。 </think> 以下是C++类中默认拷贝操作与销毁函数的详细说明: --- ### 📌 **1. 默认拷贝构造函数 (Default Copy Constructor)** 定义编译器自动生成的函数:`ClassName(const ClassName&)`。 **行为**: * 对每个成员变量执行**浅拷贝**。 * 基础类型(`int`, `double`等)直接复制值。 * 类类型成员调用其拷贝构造函数。 * 指针成员**仅拷贝地址**,不拷贝指向的数据(⚠️ 易引发双重释放或内存泄漏!)。 ```cpp class Example { int* data; int size; public: // 编译器生成的默认拷贝构造函数等效于: Example(const Example& other) : data(other.data), size(other.size) {} }; ``` --- ### 📌 **2. 默认拷贝赋值运算符 (Default Copy Assignment Operator)** 定义编译器自动生成的函数:`ClassName& operator=(const ClassName&)`。 **行为**: * 对每个成员变量执行**浅拷贝**(同拷贝构造函数)。 * 返回当前对象的引用(`return *this;`)以支持链式赋值(如`a=b=c`)[^1]。 * 若成员变量为类类型,调用其拷贝赋值运算符。 ```cpp class Example { int* data; public: // 默认拷贝赋值运算符等效于: Example& operator=(const Example& other) { data = other.data; // 直接复制指针(浅拷贝) return *this; } }; ``` --- ### 📌 **3. 默认析构函数 (Default Destructor)** 定义编译器自动生成的函数:`~ClassName()`。 **行为**: * 若成员变量为类类型,调用其析构函数。 * **不释放原始指针成员指向的动态内存**(⚠️ 导致内存泄漏!)[^3]。 * 基础类型、智能指针等能自动管理资源的成员无需额外处理[^2]。 ```cpp class ResourceHolder { int* resource; public: // 默认析构函数等效于: ~ResourceHolder() {} // resource指向的内存未释放! }; ``` --- ### ⚠️ **关键风险:浅拷贝问题** 默认拷贝操作析构函数在涉及动态资源管理(如堆内存、文件句柄)时存在严重隐患: 1. **双重释放**:两个对象持有同一指针,析构时重复删除内存 → **程序崩溃**。 2. **内存泄漏**:指针成员指向的动态资源未被释放[^3]。 3. **数据篡改**:通过一个对象修改数据会影响共享资源的其他对象。 ```cpp { Example obj1; { Example obj2 = obj1; // 默认拷贝构造:obj2.data = obj1.data } // obj2析构,释放data指向的内存 obj1.useData(); // ❌ obj1.data已成为悬空指针! } ``` --- ### 🔧 **三/五法则 (Rule of Three/Five)** 当类需自定义以下任一函数时,通常需全部显式定义以正确处理资源: 1. 析构函数 2. 拷贝构造函数 3. 拷贝赋值运算符 (C++11后增加移动构造移动赋值,合称*五法则*) ```cpp class SafeArray { int* arr; size_t sz; public: // 1. 自定义析构函数 ~SafeArray() { delete[] arr; } // 2. 自定义拷贝构造函数(深拷贝) SafeArray(const SafeArray& other) : sz(other.sz), arr(new int[sz]) { std::copy(other.arr, other.arr + sz, arr); } // 3. 自定义拷贝赋值运算符 SafeArray& operator=(const SafeArray& other) { if (this != &other) { // 避免自赋值 delete[] arr; // 释放原有资源 sz = other.sz; arr = new int[sz]; std::copy(other.arr, other.arr + sz, arr); } return *this; } }; ``` --- ### **三种默认函数行为对比** | 函数 | 触发场景 | 默认行为风险点 | |-------------------------|-----------------------------|-----------------------------| | **拷贝构造函数** | `Example b = a;` | 指针共享 → 双重释放/泄漏 | | **拷贝赋值运算符** | `b = a;` | 同上 + 原有资源未释放[^3] | | **析构函数** | 对象离开作用域 | 指针资源未释放 → 内存泄漏 | --- ### **总结** * 默认函数适合**无资源管理**的简单类(如仅含`int`, `string`等成员)。 * **管理动态资源的类必须遵循三/五法则**,自定义拷贝赋值析构函数实现深拷贝安全释放。 * C++11起可用**移动语义**(移动构造/赋值)优化资源转移效率。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值