C++ 析构函数与拷贝构造函数详解及深浅拷贝对比
C++ 类编程中,析构函数负责对象销毁时的资源清理,而拷贝构造函数决定对象复制时的行为模式。本文将通过具体代码示例,解析析构函数的调用时机与指针处理,并重点区分深拷贝与浅拷贝的实现逻辑,帮助开发者避免内存泄漏与悬空指针问题。
构造函数的定义方式
在 C++ 中,每个类默认包含一个无参构造函数(类名() {})。当用户显式定义任何构造函数时,编译器将不再自动生成默认无参构造函数。定义有参构造函数通常有两种等效写法:
class MM
{
public:
// 使用初始化列表(推荐),效率更高且支持 const 成员
MM(int year, string name) :year(year), name(name) {}
// 或在函数体内赋值
MM(int year, string name)
{
this->name = name;
this->year = year;
}
// 支持默认参数(注意:只能从右向左提供默认值)
MM(int year, string name = "") :year(year) {}
protected:
int year;
string name;
};
示例中 MM mm(15); 将创建 year=15 且 name="" 的对象。若省略默认参数则编译报错。
析构函数的职责与注意事项
~MM() 用于在对象生命周期结束时自动执行清理工作,无需手动调用。其核心规则如下:
- 资源释放:若类成员包含动态分配内存(如指针),必须在析构函数中释放该内存,否则会导致内存泄漏。
- 非指针成员:仅包含基本类型或标准库对象(如
string)的类,析构函数可为空或省略。
class MM
{
public:
MM(const char* str)
{
strcpy(this->str, str);
}
~MM() { delete[] str; } // 必须释放堆内存,否则只析构对象本身而不释放指向内容
protected:
int year;
string name;
char* str;
};
int main()
{
MM mm("kkk");
return 0; // 离开作用域时自动触发 ~MM
}
拷贝构造函数的触发场景
当使用现有对象创建新对象时,会调用拷贝构造函数,此时不经过普通构造函数。常见调用方式包括:
- 直接初始化:
MM mm1(mm); - 拷贝初始化:
MM mm2 = mm; - 匿名对象赋值:先通过构造函数创建临时对象,再将其赋值给已有对象时会隐式调用拷贝构造:
MM mm3 = MM(16, "jfsdl");
深拷贝与浅拷贝的核心差异
系统默认的拷贝构造函数仅执行逐字节赋值(即浅拷贝),这在涉及指针成员时会导致严重的安全隐患。
浅拷贝机制
仅复制指针的地址值,新旧对象指向同一块堆内存。任一对象析构时释放内存,另一对象将持有悬空指针,引发运行时错误。
// 错误示范:浅拷贝
MM(const MM& object)
{
this->str = object.str; // 地址复制,未分配新内存
}
深拷贝机制
为当前对象重新申请独立内存,并将源数据完整拷贝至新空间。此方式保证对象的资源独立性,但需在析构函数中对应释放新分配的内存。
// 正确示范:深拷贝
MM(const MM& object)
{
int len = strlen(object.str) + 1;
this->str = new char[len]; // 申请新内存
strcpy(str, object.str); // 内容拷贝
}
总结而言,处理自定义资源管理的类时,若定义了析构函数,通常需要同时重写拷贝构造函数以实现深拷贝,以确保程序安全。
以上就是C++编程析构函数拷贝构造函数使用示例详解的详细内容,更多关于C++编程析构函数拷贝构造函数的资料请关注本站其它相关文章!本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













