C++ 析构函数与拷贝构造函数详解及深浅拷贝对比

月亮慢半拍
月亮慢半拍
发布时间:2026-10-16 | 3人浏览过
原创

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() 用于在对象生命周期结束时自动执行清理工作,无需手动调用。其核心规则如下:

  1. 资源释放:若类成员包含动态分配内存(如指针),必须在析构函数中释放该内存,否则会导致内存泄漏。
  2. 非指针成员:仅包含基本类型或标准库对象(如 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++编程析构函数拷贝构造函数的资料请关注本站其它相关文章!
相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表