首页 > 系统相关 >C++中管理动态内存:析构函数中的`delete`使用指南

C++中管理动态内存:析构函数中的`delete`使用指南

时间:2024-12-22 22:28:41浏览次数:13  
标签:释放 动态内存 int C++ 动态分配 内存 析构 ptr delete

在C++编程中,正确管理动态分配的内存是至关重要的。不当的内存管理可能导致内存泄漏、野指针和重复释放等问题。本文将详细介绍如何在C++类中使用deletedelete[]来释放动态分配的资源,并提供一些最佳实践,以确保资源被安全、有效地管理。

1. 析构函数中的delete

当类的成员变量是动态分配的资源时,必须在析构函数中使用deletedelete[]来释放这些资源,以避免内存泄漏。

背景

在C++中,动态内存分配是通过newdelete操作符来管理的。new操作符用于分配内存,而delete操作符用于释放内存。如果一个对象在堆上分配了内存,那么当对象的生命周期结束时,必须确保相应的内存被释放,否则会导致内存泄漏。

示例:释放动态分配的成员

#include <iostream>
using namespace std;

class MyClass {
private:
    int* ptr; // 动态分配的成员变量
public:
    // 构造函数
    MyClass(int value) {
        ptr = new int(value); // 动态分配内存
        cout << "Constructor: allocated memory with value " << *ptr << endl;
    }

    // 析构函数
    ~MyClass() {
        delete ptr; // 释放动态分配的内存
        cout << "Destructor: released memory" << endl;
    }

    void show() const {
        cout << "Value: " << *ptr << endl;
    }
};

int main() {
    MyClass obj(42);
    obj.show();

    // 析构函数会在对象销毁时自动调用
    return 0;
}

说明:

在这个示例中,我们创建了一个名为MyClass的类,它包含一个动态分配的整数指针ptr。在构造函数中,我们使用newptr分配内存,并在析构函数中使用delete释放内存。这确保了当MyClass对象被销毁时,分配的内存也会被正确释放。

2. 管理动态数组

如果类内部管理动态数组,需要在析构函数中使用delete[]来释放内存。

背景

动态数组的分配和释放与单个对象略有不同。当使用new[]分配数组时,必须使用delete[]来释放内存。这是因为数组的构造和析构涉及到多个对象的初始化和清理。

示例:释放动态数组

#include <iostream>
using namespace std;

class ArrayClass {
private:
    int* arr; // 动态分配的数组
    int size;
public:
    // 构造函数
    ArrayClass(int n) : size(n) {
        arr = new int[size]; // 动态分配数组
        for (int i = 0; i < size; ++i) {
            arr[i] = i + 1; // 初始化数组
        }
        cout << "Constructor: allocated array of size " << size << endl;
    }

    // 析构函数
    ~ArrayClass() {
        delete[] arr; // 释放动态分配的数组
        cout << "Destructor: released array memory" << endl;
    }

    void show() const {
        for (int i = 0; i < size; ++i) {
            cout << arr[i] << " ";
        }
        cout << endl;
    }
};

int main() {
    ArrayClass obj(5);
    obj.show();

    // 析构函数会在对象销毁时自动调用
    return 0;
}

说明:

在这个示例中,我们创建了一个名为ArrayClass的类,它包含一个动态分配的整数数组arr。在构造函数中,我们使用new[]arr分配内存,并在析构函数中使用delete[]释放内存。这确保了当ArrayClass对象被销毁时,分配的数组内存也会被正确释放。

3. 防止重复释放和野指针

为了避免重复释放内存和产生野指针,常见的做法是将指针成员在释放后设置为nullptr

背景

野指针是指指向已释放内存的指针。如果一个指针被释放后没有设置为nullptr,那么它仍然指向原来的内存地址,这可能导致未定义行为,包括访问已释放的内存。

示例:避免野指针

#include <iostream>
using namespace std;

class SafeClass {
private:
    int* ptr;
public:
    SafeClass(int value) {
        ptr = new int(value);
    }

    ~SafeClass() {
        delete ptr; // 释放内存
        ptr = nullptr; // 避免野指针
    }

    void reset(int value) {
        delete ptr; // 释放旧内存
        ptr = new int(value); // 分配新内存
    }

    void show() const {
        if (ptr) {
            cout << "Value: " << *ptr << endl;
        } else {
            cout << "Pointer is null." << endl;
        }
    }
};

int main() {
    SafeClass obj(42);
    obj.show();

    obj.reset(100);
    obj.show();

    return 0;
}

说明:

在这个示例中,我们创建了一个名为SafeClass的类,它包含一个动态分配的整数指针ptr。在析构函数中,我们使用delete释放内存,并将ptr设置为nullptr,以避免野指针的产生。此外,我们还提供了一个reset方法,用于重新分配内存,这也展示了如何在释放旧内存后避免野指针。

4. 禁止拷贝

如果类中有动态分配的资源,应当禁止默认的拷贝构造函数和赋值运算符,或者实现深拷贝,防止多次释放同一块内存。

背景

默认的拷贝构造函数和赋值运算符会进行浅拷贝,这意味着它们只会复制指针的值,而不是指针指向的内存。这可能导致多个对象尝试释放同一块内存,从而导致重复释放和程序崩溃。

示例:禁止拷贝

#include <iostream>
using namespace std;

class NoCopyClass {
private:
    int* ptr;
public:
    NoCopyClass(int value) {
        ptr = new int(value);
    }

    ~NoCopyClass() {
        delete ptr;
    }

    // 禁止拷贝构造函数
    NoCopyClass(const NoCopyClass&) = delete;

    // 禁止赋值运算符
    NoCopyClass& operator=(const NoCopyClass&) = delete;

    void show() const {
        cout << "Value: " << *ptr << endl;
    }
};

int main() {
    NoCopyClass obj(42);
    obj.show();

    // NoCopyClass obj2 = obj; // 编译错误:拷贝构造函数被删除
    // obj2 = obj; // 编译错误:赋值运算符被删除

    return 0;
}

说明:

在这个示例中,我们创建了一个名为NoCopyClass的类,它包含一个动态分配的整数指针ptr。我们通过将拷贝构造函数和赋值运算符标记为delete,来禁止拷贝操作。这确保了NoCopyClass对象不能被拷贝,从而避免了多次释放同一块内存的问题。

总结

通过上述示例和说明,我们可以看到,正确管理动态内存是C++编程中的一个重要方面。使用deletedelete[]在析构函数中释放动态分配的资源,避免野指针问题,释放后将指针设置为nullptr,以及通过删除拷贝构造函数和赋值运算符防止多次释放同一块内存,都是确保程序稳定性和安全性的关键步骤。遵循这些最佳实践,可以帮助你编写更加健壮和安全的C++代码。

标签:释放,动态内存,int,C++,动态分配,内存,析构,ptr,delete
From: https://blog.csdn.net/shanxuanang/article/details/144653902

相关文章

  • c++实验6
    实验任务4#include<iostream>#include<stdexcept>template<typenameT>classVector{private:T*data;intnum;public:Vector(intsize);Vector(intsize,constT&value);Vector(constVector<T>&other);......
  • 在C#中,使用 Stopwatch 比较简单粗糙的替代 WIN32 下 C++ 中调用的 QueryPerformanceCo
    C#中自带的那个CTimer看上去是通过消息事件方式的,精度上好像小于10ms就不行了。于是找了半天网络,有的方式是引用kernel32.dll的库,然后就可以在C#中调用 QueryPerformanceCounter。感觉是不那么优雅。最后居然发现这个Stopwatch。真的像一个计时器一样,按一下,开始【Sto......
  • Java转C++之模板元编程
    模板元编程(TemplateMetaprogramming)入门指南:针对Java程序员的讲解作为一个从Java转到C++的程序员,理解模板元编程(TemplateMetaprogramming,简称TMP)可能会感到有些挑战,特别是其中的语法和概念有很多与Java非常不同的地方。模板元编程是一种强大的技术,它允许我们在编译时......
  • MFC/C++学习系列之简单记录1——错误解决与Dialog移植
    MFC/C++学习系列之简单记录1前言MFCapplication已停止工作Dialog移植MFC中的去边框设置总结前言最近接触MFC,接手一个项目,基于MFC架构编写的,在跑通代码的过程中出现的问题进行简单记录。MFCapplication已停止工作在代码移植过程中,直接build代码,提示MFCapplicat......
  • MFC/C++学习系列之简单记录8——消息映射
    MFC/C++学习系列之简单记录8——消息映射前言消息映射机制DoDataExchange函数BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏与WPF对比总结前言每天学习一点MFC的小知识!消息映射机制说起来很高大上,其实就是前端界面控件和后台代码命名的绑定。当前端控件执行某些操......
  • 【C++】剖析运算符重载和赋值运算符重载
    -----------------------------------------------------begin------------------------------------------------------运算符重载:当运算符被用于类类型的对象时,C++语言允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使⽤运算符时,必须转换成调用对应运......
  • C++超市外卖小程序-计算机设计毕业源码62482
    摘要随着社会生活节奏加快和消费习惯的变化,外卖服务成为人们日常生活中不可或缺的一部分。超市外卖作为新兴业态备受关注,然而传统外卖平台在推荐精准度和用户体验方面存在挑战。本研究旨在基于协同过滤算法,结合C++语言和MySQL数据库,设计开发一款超市外卖小程序,以提升用户点......
  • C++, 模板元编程, 凭借辅助的模板结构的特化 , 从而以类型控制模板类的分支
    u++真是学无止境,遍地地雷,哦不,遍地黄金。看ue序列化中的TArray有感,特节取部分代码保存,希望能多切近ue的编码经验半分。 //...template<typenameT>structTCanBulkSerialize{enum{Value=false};};template<>structTCanBulkSerialize<unsignedint>{enum{Value......
  • C++模板--类模板
    一篇文章带你走进类模板的世界!!!前言上一篇文章的链接:https://blog.csdn.net/hujiahangdewa/article/details/144630185有了上一篇文章的铺垫,我们再来看看类模板。其实就是要看template这段代码的后面跟的是什么,如果跟的是函数的定义,那么它就是一个函数模板,如果跟的是......
  • 【c++修炼之路】从零到英雄:c++的传奇进化史
      ......