new 和 delete 是 C++ 用于管理 堆内存 的两个运算符,对应于 C 语言中的 malloc 和 free,但是 malloc 和 free 是函数,new 和 delete 是运算符。除此之外,

new 在申请内存的同时,还会调用对象的构造函数,而 malloc 只会申请内存;

delete 在释放内存之前,会调用对象的析构函数,而 free 只会释放内存。

new 运算符的内部实现分为两步

  • 内存分配

    调用相应的 operator new(size_t) 函数,动态分配内存。如果 operator new(size_t) 不能成功获得内存,则调用 new_handler() 函数用于处理new失败问题。如果没有设置 new_handler() 函数或者 new_handler() 未能分配足够内存,则抛出 std::bad_alloc 异常。“new运算符”所调用的 operator new(size_t) 函数,按照C++的名字查找规则,首先做依赖于实参的名字查找(即ADL规则),在要申请内存的数据类型T的 内部(成员函数)、数据类型T定义处的命名空间查找;如果没有查找到,则直接调用全局的 ::operator new(size_t) 函数。

  • 构造函数

    在分配到的动态内存块上 初始化 相应类型的对象(构造函数)并返回其首地址。如果调用构造函数初始化对象时抛出异常,则自动调用 operator delete(void*, void*) 函数释放已经分配到的内存。

delete 运算符的内部实现分为两步:

  • 析构函数

    调用相应类型的析构函数,处理类内部可能涉及的资源释放。

  • 内存释放

    调用相应的 operator delete(void *) 函数。调用顺序参考上述 operator new(size_t) 函数(ADL规则)。

class T{
public:
T(){
cout << "构造函数。" << endl;
} ~T(){
cout << "析构函数。" << endl;
} void * operator new(size_t sz){
T * t = (T*)malloc(sizeof(T));
cout << "内存分配。" << endl;
return t;
} void operator delete(void *p){
free(p);
cout << "内存释放。" << endl;
return;
}
}; int main()
{
T * t = new T(); // 先 内存分配 ,再 构造函数
delete t; // 先 析构函数, 再 内存释放
return 0;
}

  

在函数执行时,new和delete的调用顺序(工作机制)

使用new表达式时发生的三个步骤:

  1、调用名为operator new的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的一个对象(自定义的new)

  2、运行该类型的一个构造函数去初始化对象

  3、返回指向新分配并构造的构造函数对象的指针

使用delete表达式时,发生的步骤:

  1、调用对象的析构函数

  2、调用名为operator delete的标准库函数释放该对象所用的内存(自定义的delete)

注意:

free只能释放基础类型的内存资源;

delete在free功能的基础上,增加了对类资源内存空间的处理。

operator new和delete的库函数

operator new 和operator delete函数有两个重载版本

void * operator new (size_t);

void * operator new[](size_t);

void operator delete(void *);

void operator delete[](void *);

高级用法

只能生成栈对象

只能生成栈对象,就是说不能生成堆对象,亦即不能通过new表达式[在类之外]生成对象。

不能生成堆对象能想到的方法:

  1、将构造函数放入private区域(不使用这种)

  2、operator new函数 放入到private区域

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h> class Student
{
public:
int iId;
char szName[10];
public:
Student() {
std::cout << "Student 构造函数被调用" << std::endl;
} ~Student()
{
std::cout << "Student 析构函数被调用" << std::endl;
} private:
static void* operator new(std::size_t nSize);
static void operator delete(void *pVoid); /*
static void* operator new(std::size_t nSize)
{
std::cout << "new 操作符被调用, size = " << nSize << std::endl;
//void *pRet = new char[nSize];
void *pRet = malloc(nSize);
return pRet;
}
static void operator delete(void *pVoid)
{
std::cout << "delete操作符被调用." << std::endl;
free(pVoid);
}
*/
}; int main(void)
{
Student *pstu = new Student;
pstu->iId = 101;
strcpy(pstu->szName, "Tony");
std::cout << std::endl;
delete pstu; //std::cout << std::endl;
//Teacher *pt = new Teacher(); //delete pt;
return 0;
}  

只能生成堆对象

只能生成堆对象,就是说不能生成栈对象,亦即在创建栈对象时,不能[在类之外]调用构造函数或者析构函数。

不能生成栈对象能想到的方法:

  1、将构造函数放到private区域(不使用这种)

  2、将析构函数放到private区域 a)对于堆对象而言,执行delete表达式无法通过编译 b)在public区域定义一个destroy()

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h> class Student
{
public:
int iId;
char szName[10];
public:
Student()
{
std::cout << "Student 构造函数被调用" << std::endl;
} void destroy()
{
//(*this).~Student();//不能清理自定义new开辟的空间
delete this;
} private://不能生成栈对象
~Student()
{
std::cout << "Student 析构函数被调用" << std::endl;
} }; class Teacher
{ }; int main(void)
{
Student *pstu = new Student;
pstu->iId = 101;
strcpy(pstu->szName, "Tony"); pstu->destroy();
delete pstu; //Student stu; return 0;
}  

小结:

1、创建栈对象

 栈对象的生成同时需要构造函数和析构函数都是public的。

  Point pt(1,2);//ok

  Poiint * p =new Point(1,2);//error

2、定义一个类,只能在栈上创建

 把operator new/delete放在private区域

  Point pt(1,2);//error

3、定义一个类只能在对上创建

 将析构函数私有化

 堆对象回收的时候,要再定义一个成员函数来销毁堆对象。

 

C++之new和delete的更多相关文章

  1. 如何区别数据库删除语句drop与delete与truncate?

    1.delete:删除数据表中的行(可以删除某一行,也可以在不删除数据表的情况下删除所有行) 删除某一行:delete from 数据表名称 where 列名称=值: 删除所有行:delete*fro ...

  2. 数据库设计中的Soft Delete模式

    最近几天有点忙,所以我们今天来一篇短的,简单地介绍一下数据库设计中的一种模式——Soft Delete. 可以说,该模式毁誉参半,甚至有非常多的人认为该模式是一个Anti-Pattern.因此在本篇文 ...

  3. 关于JavaScript中的delete操作

    关于JavaScript中的delete操作 看到一道题,是这样的: (function(x){ delete x; return x; })(1); 1 null undefined Error 我 ...

  4. Git异常:Cannot delete the branch 'test1' which you are currently on

    GitHub实战系列汇总:http://www.cnblogs.com/dunitian/p/5038719.html ———————————————————————————————————————— ...

  5. HTTP Method详细解读(`GET` `HEAD` `POST` `OPTIONS` `PUT` `DELETE` `TRACE` `CONNECT`)

    前言 HTTP Method的历史: HTTP 0.9 这个版本只有GET方法 HTTP 1.0 这个版本有GET HEAD POST这三个方法 HTTP 1.1 这个版本是当前版本,包含GET HE ...

  6. IIS7.5上的REST服务的Put,Delete操作发生HTTP Error 405.0 - Method Not Allowed 解决方法

    WebDAV 是超文本传输协议 (HTTP) 的一组扩展,为 Internet 上计算机之间的编辑和文件管理提供了标准.利用这个协议用户可以通过Web进行远程的基本文件操作,如拷贝.移动.删除等.在I ...

  7. ASP.NET Core 中文文档 第二章 指南(4.10)检查自动生成的Detail方法和Delete方法

    原文 Examining the Details and Delete methods 作者 Rick Anderson 翻译 谢炀(Kiler) 校对 许登洋(Seay).姚阿勇(Mr.Yao) 打 ...

  8. new/delete重载

    在c++中,有时我们需要在运行阶段为一个变量分配未命名的内存,并使用指针来访问它,这里就可以用到new关键字.另外需要指出的是,new分配的内存块通常与常规变量分配的内存块不同,常规变量的值都储存在被 ...

  9. EC笔记:第三部分:16成对使用new和delete

    我们都知道,申请的资源,使用完毕后要释放.但是这个释放动作,一定要注意. 举个例子,很多人动态分配的资源,在使用之后,往往直接调用了delete,而不管申请资源的时候用的是new还是new[]. 如下 ...

  10. Spring boot: Request method 'DELETE' not supported, Request method 'PUT' not supported, Request method 'POST' not supported

    GET,POST,PUT,DELETE, Spring都支持,不要怀疑Spring, 一定是前端发送的rest 请求和后端的响应不匹配, 查找原因以及解决办法, 很简单 用chrome打开F12控制台 ...

随机推荐

  1. Git以及github的使用方法(五),暂存区和工作区

    Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念. 先来看名词解释. 工作区(Working Directory) 就是你在电脑里能看到的目录,比如我的learngit文件夹就是一个工 ...

  2. poj Kindergarten

    Kindergarten 又是一道自己没思考出来的题 !!!!! 还是老样子,题目去我拉的专题里有. 题目: 给出G给女孩,B给男孩.女孩之间是相互认识的,男孩之间也是相互认识的.如今题目中给出M对男 ...

  3. fuser - identify processes using files or sockets

    FUSER(1) User Commands FUSER(1) NAME fuser - identify processes using files or sockets SYNOPSIS fuse ...

  4. uboot下载地址

    非常奇怪百度搜索都搜不到一个好的uboot下载的说明,仅此标记 HOME http://www.denx.de/wiki/U-Boot/SourceCode sourcecode http://www ...

  5. oracle sql修改序列为当前序列开始

    declare   v_num integer;  last_value integer;Begin  select SEQ_TBM_ID.NEXTVAL into last_value from d ...

  6. node开发后将本地mysql数据导入到服务器mysql

    近期写的一个钉钉企业微应用用到了mysql数据库(用koa写的后台,并用mysql库来连接),现在需要把本地数据库的数据导入到服务器的数据库中. 服务器安装mysql 可以google篇centos的 ...

  7. ffmpeg推送,EasyDarwin转发,vlc播放 实现整个RTSP直播

    部署EasyDarwin流媒体服务器 ffmpeg推送摄像机视频到EasyDarwin VLC播放 第一步:部署EasyDarwin流媒体服务器 EasyDarwin的部署过程我们就不再赘述了,在Ea ...

  8. Pipeline inbound(netty源码7)

    netty源码死磕7  Pipeline 入站流程详解 1. Pipeline的入站流程 在讲解入站处理流程前,先脑补和铺垫一下两个知识点: (1)如何向Pipeline添加一个Handler节点 ( ...

  9. intelliJ IDEA springMVC 搭建配置

    1.添加参数 archetypeCatalog=internal

  10. Tomcat启动过程中卡住了

    我在部署完项目后,debug启动Tomcat会在中间卡住不继续执行,测试发现在不部署项目的时候Tomcat是可以正常启动的. 控制台信息如下: 十月 25, 2017 10:40:44 上午 org. ...