我的编程空间,编程开发者的网络收藏夹
学习永远不晚

c++中的new和delete怎么用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

c++中的new和delete怎么用

小编给大家分享一下c++中的new和delete怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

new expression

new一个类型,会创建一个该类型的内存,然后调用构造函数,最后返回该内存的指针

注意:该操作是原子性的。

在vc6中的实现如下

void *operator new(size_t size, const std::nothrow_t &) _THROW0(){    void *p    while((p = malloc(size)) == 0)    {        // 如果调用malloc失败后会调用_callnewh        // _callnewh含义是call new handler,简单说就是用户设定一个回调函数        // 使用_set_new_handler来设置,通常是用户自己控制释放一些不用的内存        _TRY_BEGIT            if(_callnewh(size) == 0) break;        _CATCH(std::bad_alloc) return (0);        _CATCH_END    }    return (p);}

delete expression

delete 一个指针,先调用析构函数,然后释放内存

在vc6中的实现如下

void *operator delete(void *p) _THROW0(){    free(p);}

new[]和new()

new[]是分配指针数组,new()是分配时直接初始化,这两个很容易搞混,关键是编译都能过,一定要注意。比如:

int *p = new[3]; // 是分配三个int*指针所组成的指针数组int *q = new(3); // 是分配一个int堆内存,并初始化为3

new[]和delete[]

Complex *pca = new Complex[3];

调用三次Complex的构造函数,分配三个Complex对象

delete[] pca;

释放内存。

如果这里的delete[]只写写成delete会怎么样?好多人一定会说:会内存泄露。

其实正确的答案是不确定,具体需要看Complex类的内部有没有堆内存

new[]后内存是怎么样的呢?看下图

c++中的new和delete怎么用

关键是看图中的cookie部分,存放了一些内存相关的数据,其中最关键的是在cookie中存放了分配内存的大小

再来看一下下面的代码

string *psa = new string[3];delete psa;

执行完该代码后内存分配如下

c++中的new和delete怎么用

由于string类的内部使用动态堆内存来保存字符串,new[]分配的内存的cookie只记录了string类的信息,而类内部的动态堆内存信息由每个实例自行管理,不在new[]的cookie中。

前面说过,delete释放内存的过程是先调用析构函数,再释放内存。在本例中,如果使用delete[]来释放内存,会依次调用每个实例的析构函数,每个析构函数会自行释放自己内部的堆内存,然后在释放new的内存块。但是如果使用delete来释放内存,只会是第一个实例调用一次析构函数,另外两个实例不会调用,然后根据cookie中记录的内存大小释放有new分配的内存,另两个实例中的堆内存就泄露了。

也就是说,对于上图string的例子,如果使用delete直接释放内存,泄露的是str2和str3箭头右边的白色区域所示的内存,而pas箭头右边的绿色区域是能够正确释放的(具体是调用的str1还是str3取决于编译器的具体实现,理解意思即可)。

但是,这不意味着你可以在类内部没有堆内存的情况下就可以毫无顾忌的使用delete来释放new[],这是编码规范的问题,使用delete不一定有错,但使用delete[]则是一定没错。

new的内存分布

下图是vc6中new的内存布局

c++中的new和delete怎么用

我们得到的是图中0x00441c30这一部分的指针,但实际上内存管理的是图中所有的一大块内存,其中橘黄色部分只有在debug模式下才有。由于内存管理需要是16的倍数,如果不够16的倍数,则添加一些数据凑到16的倍数,图中蓝色的pad部分就是添加的无用数据。图中61h部分就是cookie,上下部分分别为上cookie和下cookie。由于本例使用的是int类型举例,而int没有析构不析构的,所以可以直接使用delete就能完整释放整块内存。这里这么写是为了让读者加深理解,实际编码的时候要加上[],这里对比一下下图

c++中的new和delete怎么用

这张图使用的类型是一个类,用new[]分配内存的时候,返回的指针和调试信息中间多出来一块内存用来记录实例的个数,就是图中的3。这中情况,如果使用delete[]来释放内存,会正确索引到实例的首地址进行释放操作,如果使用delete来释放内存,索引到的内存是记录实例个数的整型数据位置,如果从这里开始按找该类的内存结构进行析构,肯定是会出问题的,整个内存结构都乱了。

这里有个地方需要注意,这里的delete和delete[]部分看起来和new[]和delete[]小结中介绍的有些矛盾,老师是怎么讲的,由于是看的盗版网课,也没办法请教老师,具体是怎么情况我也不太清楚。猜测是因为不同编译器具体实现时,3的位置不同,有的在前面,有的在后面,关键是看具体实现,在前面的情况就是矛盾的,在后面就没事,关键是领会精神。

placement new

placement new 允许我们将对象构建于一个已经分配的内存当中

没有所谓的placement delete,因为placement根本就没有分配内存,它只是使用了一个已经分配好的内存,所以不需要配套的释放操作,具体用法如下

#include <new>// 分配内存char *buf = new char[sizeof(Complex) * 3];// 在分配好的内存上构造ComplexComplex *pc = new(buf)Complex(1, 2);// 注意这里要释放的指针// 感觉如果直接释放pc应该也没错// 手上没环境不能测试,以后有时间测一下delete[] buf;

new失败处理

在纯C中使用malloc来分配内存,需要判断一下返回的指针,如果返回一个空指针,则代表内存分配失败。

到了c艹中,使用new来分配内存,则无法通过判断空指针的方法判断是否失败。因为在c艹中,如果new失败会抛出异常,代码是走不到判断空指针的语句的。new失败正确处理方法有以下几种

捕捉异常

try {    int* p = new int[SIZE];    // 其它代码} catch ( const bad_alloc& e ) {    return -1;}

据说古老的c++编译器new失败不会抛异常,而是和malloc一样返回空指针,因为那时候c++还没有异常机制,坊间流传,也懒得考证,了解以下即可。顺便吐槽一下,说c艹的异常是屎,这是对屎的侮辱,屎还能当肥料种地呢,c艹的异常除了捣乱没任何鸟用。

禁用new的异常

 int* p = new (std::nothrow) int; // 这样如果 new 失败了,就不会抛出异常,而是返回空指针

new-handler

文章开始介绍new源码的时候提到过,new实现的时候会调用new-handler的回调函数,在new之前设置好回调函数即可。由于此方法太过麻烦,懒得研究,具体用法读者自行查找相关资料。

重载

c++中的new和delete怎么用

重载的时候,一般不重载全局的::operator new,因为全局的影响太大,一般只重载类自身的Foo::operator new。

重载一般在内存池中用的比较多,可以减少cookie

重载全局的::operator new

void *myAlloc(size_t size){ return malloc(size); }void myFree(void *p){ free(p); }// 下面代码实现部分不重要,关键看接口的重载// 它们不可以被声明在一个namespace内inline void *operator new(size_t size){ cout << "global new()\n"; return myAlloc(size); }inline void *operator new[](size_t size){ cout << "global new[]()\n"; return myAlloc(size); }inline void operator delete(void *p){ cout << "global delete()\n"; return myFree(p); }inline void operator delete[](void *p){ cout << "global delete[]()\n"; return myFree(p); }

重载局部的Foo::operator new

class Foo{public:    void *operator new(size_t);    void operator delete(void*);};

需要注意的是,重载局部的new和delete必须是static的,因为new调用时是内存对象创建过程当中,此时还没有一个完整的内存对象,无法通过对象来调用一般的函数。由于必须是static的,不管写不写static,编译器都会当成是static处理。

数组版本也是一样的,只是都加了一个[],这里就不再写一次了

重载placement new

placement new的括号中不一定非要放指针,我们可以自己来定义放任意的东西。放指针的版本是标准库中先写好给我们用的,我们也可以通过重载placement new来自定义所放的数据,比如Foo *pf = new(300, 'c')Foo;。可以重载为多种参数形式,但多个重载的参数列形式不能重复,必须满足普通函数重载的条件。其中第一个参数必须是size_t,用来传递类的大小,该参数类似于成员函数的this指针,在调用时自动传递,不需要显示传递。比如在Foo *pf = new(300, 'c')Foo;中,其声明形式为void *operator new(size_t, int, char);。如果内存不是外部申请好的,需要在placement new函数内部去申请内存。

重载new的时候应该对应重载一个相同形式的delete。但重载placement delete时需要注意,只有在placement new中产生异常,才会调用其对应的placement delete函数。c++这么设计的原因是,在调用placement new函数后,如果内存是由在placement new内申请的,在调用构造函数时如果发生了异常,可以在对应的在placement delete函数中将在placement new中申请的内存释放掉。

如果没有对应形式的delete,编译器也不会报错,编译器会认为你放弃处理该形式的new中产生的异常(个别编译器会给个警告)

class Foo{public:    // 重载一个一般形式的operator new    void *operator new(size_t);    // 标准库中placement new的重载形式    void *operator new(size_t, void *);    // Foo *pf = new(300, 'c')Foo;调用形式的重载方式    void *operator new(size_t, int, char);    // 随便写的一种重载形式    void *operator new(size_t, size_t, char *, int);    // 以下是对应的delete    void *operator delete(void *, size_t);    void *operator delete(void *, void *);    void *operator delete(void *, int, char);    void *operator delete(void *, size_t, char *, int);};

std::string中就是一个很好的placement new重载,有兴趣的朋友可以去看string的源码

c++ new与malloc的10点差别表格:

特征new/deletemalloc/free
分配内存的位置自由存储区
内存分配失败返回值完整类型指针void*
内存分配失败返回值默认抛出异常返回NULL
分配内存的大小由编译器根据类型计算得出必须显式指定字节数
处理数组有处理数组的new版本new[]需要用户计算数组的大小后进行内存分配
已分配内存的扩充无法直观地处理使用realloc简单完成
是否相互调用可以,看具体的operator new/delete实现不可调用new
分配内存时内存不足客户能够指定处理函数或重新制定分配器无法通过用户代码进行处理
函数重载允许不允许
构造函数与析构函数调用不调用

malloc给你的就好像一块原始的土地,你要种什么需要自己在土地上来播种

而new帮你划好了田地的分块(数组),帮你播了种(构造函数),还提供其他的设施给你使用:

当然,malloc并不是说比不上new,它们各自有适用的地方。在C++这种偏重OOP的语言,使用new/delete自然是更合适的。

以上是“c++中的new和delete怎么用”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网行业资讯频道!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

c++中的new和delete怎么用

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

c++中的new和delete怎么用

小编给大家分享一下c++中的new和delete怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!new expressionnew一个类型,会创建一个该类型的
2023-06-22

c++中new和delete怎么使用

在C++中,new和delete是用来动态分配和释放内存的操作符。1. 使用new操作符动态分配内存:```int* p = new int; // 分配一个int类型的内存空间,并将其地址赋给指针p```在这个例子中,new操作符会在堆上
2023-09-27

C++的new和delete使用示例详解

这篇文章主要为大家介绍了C++的new和delete使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-12-08

C++中new和delete匹配使用过程详解

关于new和delete的使用相信大家并不陌生,可是为什么使用new的时候要用delete,使用new[]的时候又要用delete[]呢?本文就来和大家详细说说
2023-02-14

C++ 内存管理:何时使用 new 和 delete

c++++ 中使用 new 和 delete 来管理内存。new 用来在堆内存中动态分配对象,delete 用来释放使用 new 分配的内存块,避免内存泄漏。new 运算符向操作系统请求内存并返回指针;delete 运算符归还指向内存块的指
C++ 内存管理:何时使用 new 和 delete
2024-05-04

你知道C++中new和delete为什么要匹配使用吗

关于new和delete的使用相信大家并不陌生,可是为什么使用new的时候要用delete,使用new[]的时候又要用delete[]呢?本文就来和大家详细说说
2023-01-10

C++中的opeartor new和placement new使用步骤

这篇文章主要介绍了C++中的opeartor new和placement new详解,在很多情况下,placement new的使用方法和其他普通的new有所不同。这里提供了它的使用步骤,需要的朋友可以参考下
2022-11-13

C++中怎么使用new和delete进行动态内存分配与数组封装

这篇文章主要讲解了“C++中怎么使用new和delete进行动态内存分配与数组封装”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++中怎么使用new和delete进行动态内存分配与数组封装
2023-06-29

c++中new的作用

c++ 中 new 运算符用于动态分配内存,包括:分配指定大小的内存块、创建堆内存中的对象以及返回指向分配内存块的指针,语法为 type* ptr = new type;。C++ 中 new 的作用new 是 C++ 中的一个运算符,用于
c++中new的作用
2024-04-26

c#中new的作用

c# 中 new 关键字用于创建类的实例,包括分配内存、调用构造函数并返回对新创建对象引用的三大操作。主要应用场景为:创建基本数据类型、创建引用类型、创建数组以及为变量分配值。C# 中 new 关键字的作用在 C# 中,new 关键字用于
c#中new的作用
2024-05-15

c++中的new的用法

c++ 中 new 运算符用于动态内存分配,从堆内存分配指定大小的内存并返回指向分配内存的指针。使用方法包括:1. 分配内存:使用 new 运算符分配所需大小的内存;2. 访问分配的内存:通过返回的指针访问分配的内存;3. 释放分配的内存:
c++中的new的用法
2024-04-26

c++中malloc和new的区别

malloc和new在c++中的主要区别在于:malloc分配的内存需手动释放,而new分配的内存自动释放。malloc分配失败返回null,new分配失败抛出异常。new自动初始化分配的内存,malloc分配的内存需要手动初始化。new支
c++中malloc和new的区别
2024-05-01

c++中,new和malloc的区别

new 和 malloc 的区别:new 是类型安全的 c++ 运算符,用于创建指定类型的对象,返回指向对象的指针。malloc 是 c 标准库函数,用于分配未类型的内存块,返回指向该内存块的 void* 指针。new 会调用构造和析构函数
c++中,new和malloc的区别
2024-05-01

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录