热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

new/delete完美内存释放

一、newdelete在c中新增了newdelete关键字,当我们定义了一个类ClassTest;时,autotestnewTestNew()这条语句将

一、new/delete     

    在c++中新增了new/delete关键字,当我们定义了一个类Class Test;时,auto  test = new TestNew() 这条语句将会执行Test的构造函数默认构造函数,例如:

class TestNew
{
public:TestNew(){_i &#61; 0;_c &#61; 0;std::cout <<_i <<_c;}~TestNew(){}private:int _i;float _c;
};int main()
{auto test_new &#61; new TestNew();return 0;
}

     实际上  new和delete操作都分为两步&#xff0c;new 操作首先 malloc sizeof(TestNew)大小的内存空间&#xff0c;再去执行TestNew()构造函数。同时delete test_new 操作是先执行~TestNew(&#xff09;操作&#xff0c;再执行free&#xff08;test_new&#xff09;操作。 所以导致了一些问题的出现&#xff0c;举例如下&#xff1a;

class TestNew
{
public:TestNew(){_i &#61; new int[10];_c &#61; 0;std::cout <<"TestNew()" <};int main()
{void *p &#61; new TestNew();delete p;return 0;
}

运行结果&#xff1a;

    该代码用void* 指针去指向 new TestNew()&#xff0c; 导致调用的构造函数&#xff0c;而没有调用析构函数&#xff0c;同时构造函数中分配的内存&#xff0c;在析构函数中没有正确执行&#xff0c;导致了内存泄漏。

二、常见用法

    而如下结构是经常用的&#xff1a;

struct Data
{~Data(){delete _data;_size &#61; 0;}void *_data; // 指针int _size; // 大小
};template
void AddData(std::list &list_data)
{void* t &#61; new T();Data *data &#61; new Data();data._data &#61; t;data._size &#61; sizeof(T);list_data.push_back(data);
}int main()
{std::list list_data;AddData(list_data);AddData(list_data);AddData(list_data);for (auto iter &#61; list_data.begin(); iter !&#61; list_data.end(); iter&#43;&#43;){delete *iter;}return 0;
}

实现一个可以增加任何数据的list&#xff0c;此时int和double是可以正常释放的&#xff0c;而TestNew是不能释放成功&#xff0c;能够正常释放的空间只有

sizeof(TestNew);如何解决这个问题成为不定参数列表的关键。事实上stl中的内存分配都不通过new/delete来进行&#xff0c;因为这本来就两步操作&#xff0c;stl分配方式如下&#xff1a;


  1. allocator与类绑定&#xff0c;因为allocator是一个泛型类
  2. allocate()申请指定大小空间
  3. construct()构建对象&#xff0c;其参数为可变参数&#xff0c;所以可以选择匹配的构造函数
  4. 使用&#xff0c;与其它指针使用无异
  5. destroy()析构对象&#xff0c;此时空间还是可以使用
  6. deallocate()回收空间

虽然增加了一步&#xff0c;但大体流程还是先分配内存&#xff0c;再构造对象。

三、解决方案&#xff08;2019.6.26增加&#xff09;

       既然是因为无法调用到析构函数导致内存泄漏&#xff0c;所有我们可以采取手动去调用析构函数的方法&#xff0c;定义一个泛型类&#xff0c;包装需要构造的函数&#xff0c;同时增加一个头指针&#xff0c;指向析构函数&#xff0c;在消耗这个对象时&#xff0c;可以先手动执行析构函数&#xff0c;再释放内存&#xff08;具体实现待添加...&#xff09;

template
struct data_construct_child;
struct data_construct
{templatestatic int size(){return sizeof(T) &#43; sizeof(void*);}templatestatic void* construct(const T& data, void *memory &#61; nullptr){if (memory &#61;&#61; nullptr) memory &#61; new char[size()];*((void **)memory) &#61; data_construct_child::get_instance();char *p_data &#61; (char*)memory &#43; sizeof(void*);new (p_data) T(data);return (void*)memory;}templatestatic T& get_value(void *p){T *t &#61; (T*)((char*)p &#43; sizeof(void*));return *t;}static void destruct(void *memory, bool delete_memory &#61; true){data_construct *constructs &#61; (data_construct *)*((void**)memory);constructs->call_destruct((char*)memory &#43; sizeof(void*));if (delete_memory) delete[] memory;}virtual void call_destruct(void *p) &#61; 0;
};template
struct data_construct_child : public data_construct
{static data_construct_child * get_instance(){static data_construct_child instance;return &instance;}virtual void call_destruct(void *p){T *t &#61; (T*)p;t->~T();}};class TestNew
{
public:TestNew(){_i &#61; new int[10];_c &#61; 0;std::cout <<"TestNew()" <};struct Data
{~Data(){data_construct::destruct(_data);_size &#61; 0;}void *_data; // 指针int _size; // 大小
};template
void AddData(std::list &list_data)
{T t;void* pp &#61; data_construct::construct(t);auto data &#61; new Data();data->_data &#61; pp;data->_size &#61; data_construct::size();list_data.push_back(data);
}int main()
{std::list list_data;AddData(list_data);AddData(list_data);AddData(list_data);for (auto iter &#61; list_data.begin(); iter !&#61; list_data.end(); iter&#43;&#43;){delete *iter;}return 0;
}

         通过一个模板类&#xff0c;在封装分配内存和执行构造、析构函数两步&#xff0c;达到完美内存释放的目的

         运行结果如下&#xff1a;

          

从结果上看&#xff0c;已经实现调用了析构函数&#xff0c;再删除内存&#xff0c;这两步&#xff0c;同时也可以只调用析构函数不删除对象内存。


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • 本文介绍了Java中Currency类的getInstance()方法,该方法用于检索给定货币代码的该货币的实例。文章详细解释了方法的语法、参数、返回值和异常,并提供了一个示例程序来说明该方法的工作原理。 ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • PHP中的单例模式与静态变量的区别及使用方法
    本文介绍了PHP中的单例模式与静态变量的区别及使用方法。在PHP中,静态变量的存活周期仅仅是每次PHP的会话周期,与Java、C++不同。静态变量在PHP中的作用域仅限于当前文件内,在函数或类中可以传递变量。本文还通过示例代码解释了静态变量在函数和类中的使用方法,并说明了静态变量的生命周期与结构体的生命周期相关联。同时,本文还介绍了静态变量在类中的使用方法,并通过示例代码展示了如何在类中使用静态变量。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 模板引擎StringTemplate的使用方法和特点
    本文介绍了模板引擎StringTemplate的使用方法和特点,包括强制Model和View的分离、Lazy-Evaluation、Recursive enable等。同时,还介绍了StringTemplate语法中的属性和普通字符的使用方法,并提供了向模板填充属性的示例代码。 ... [详细]
author-avatar
储兰兰快乐
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有