一、new的浅析

在C++中,new主要由三种形式:new operator、operator new和placement new


• new operator

new operator即一些C++书籍中(如《C++ Primer》)所说的new表达式(new expression) ,也是我们在C++中用来进行动态内存空间开辟的主要工具。

语法:

语法1:类型* 指针名=new 类型 //在内存的堆区动态开辟一个变量大小的空间
语法2:类型* 指针名=new 类型(初始化值) //在内存的堆区动态开辟一个变量大小的空间,并对该动态变量进行初始化
语法3:类型*指针名=new 类型[数组大小] //在内存的堆区动态开辟一个数组大小的空间

示例:

 int *value=new int; //语法1示例
string *name=new string("Tomwenxing"); //语法2示例
double *array=new int[]; //语法3示例

事实上,当我们使用new来开在内存中动态开辟空间时,new operator主要完成了三项工作:

1.在内存的堆区中动态开辟空间(由operator new来完成,很多编译其借助C语言中的malloc来实现)

2.调用构造函数(C语言中的malloc只开辟空间而不调用构造函数,这也是为什么new可以进行初始化而malloc不行的原因)

 #include<iostream>
#include<string>
using namespace std;
class Student{
public:
Student(){
cout<<"调用默认构造函数"<<endl;
}
Student(string name):Name(name){
cout<<"调用带参数的构造函数"<<endl;
}
private:
string Name;
}; int main(){
Student *stu1=new Student;
Student *stu2=new Student("Tomwenxing");
delete stu1;
delete stu2;
return ;
}

3.返回分配的指针(C语言的malloc只返回void*指针,而new返回的指针都有特定的类型而非空指针)

特别注意:new operator=operator new+Constructor(构造函数)


 • operator new

new operator的第一步在内存的堆区动态开辟内存实际上就是通过operator new来完成的。通常情况下,new operator的声明如下:

void* operator new(size_t size);

特别注意:

1.operator new的返回值类型是void* ,表示operator new的返回值是一个指向一块原始的未设置初始值的内存。换句话说,operator new的唯一任务就是负责内存分配;而获取operator new返回的内存并将之转换为一个对象则是new operator的责任。

2.operator new中的size_t参数表示的是需要分配的内存的大小;我们可以将operator new进行重载,甚至添加额外的参数,但operator new的第一个参数的类型必须总是size_t  [注]:operator new的size_t参数的大小一般由系统根据实际类型调用sizeof计算得来

 #include<iostream>
#include<string>
using namespace std;
class Student{
public:
Student(){
cout<<"调用默认构造函数"<<endl;
}
Student(string name):Name(name){
cout<<"调用带参数的构造函数"<<endl;
}
12 void* operator new(size_t size){ //对operator new进行了重载
13 cout<<"调用了operator new"<<endl;
14 return malloc(size);
15 }
private:
string Name;
}; int main(){
Student *stu1=new Student;
cout<<"---------分界线-----------------"<<endl;
Student *stu2=new Student("Tomwenxing");
delete stu1;
delete stu2;
return ;
}

3.利用new创建动态数组时无法对数组中的元素显式初始化(也就是说只能调用默认构造函数,而不能调用带参数的构造函数),并且可以对new[]进行单独的重载。

 #include<iostream>
#include<string>
using namespace std;
class Student{
public:
Student(){
7 cout<<"调用默认构造函数"<<endl;
}
Student(string name):Name(name){
cout<<"调用带参数的构造函数"<<endl;
}
void* operator new(size_t size){ //重载operator new
cout<<"调用了operator new"<<endl;
return malloc(size);
}
16 void* operator new[](size_t size){ //重载operator new[]
17 cout<<"调用operator new[]"<<endl;
18 return malloc(size);
19 }
private:
string Name;
}; int main(){
Student *stu=new Student[];
delete []stu;
return ;
}

4.可以像调用其他普通函数一样,手动的调用operator new,例如:

 void* name=operator new(sizeof(string));

这里的operator new将返回指针,指向一块足够容纳一个string对像的内存


• placement new

从本质上来讲,placement new是对operator new的一个重载,它的声明如下:

void* operator new(size_t size,void* ptr);

特别注意:

1.与operator new不同,placement new定义在头文件"new.h"中,并且相比与operator new多接受一个void* 型指针参数ptr,但它也只是简单地将指针ptr返回。

placement new在头文件new.h中的源代码:

2.placement new可以在其参数指针ptr所指地址上构建一个对象(通过调用其构造函数)从而实现定位构造,也就是说placement new可以在取得一块可以容纳指定类型的对象的内存后,在这块内存上手动构造该类型的对象。而new operator的第二步(调用构造函数)通常就是通过placement new来实现的

3.placement new的调用语法:

语法1:new(指针) 类() //调用默认构造函数
语法2:new(指针) 类(参数) //调用带参数的构造函数

示例:

 #include<iostream>
#include<string>
#include<new>
using namespace std;
class Student{
public:
Student(){
cout<<"调用默认构造函数"<<endl;
}
Student(string name):Name(name){
cout<<"调用带参数的构造函数"<<endl;
}
private:
string Name;
}; void* operator new(size_t size){ //重载operator new
cout<<"调用了operator new"<<endl;
return malloc(size);
}
int main(){
//Student *stu1=new Studdent;
23 Student *stu1=(Student*)::operator new(sizeof(Student));
24 new(stu1) Student();
delete stu1;
cout<<"---------分界线--------------"<<endl;
//Student *stu2=new Student("Tomwenxing");
28 Student *stu2=(Student*)::operator new(sizeof(Student));
29 new(stu2) Student("Tomwenxing");
delete stu2;
return ;
}

4.placement new虽然实现了在指定内存地址上用指定类型的构造函数来构造一个对象的功能,但除非特别必要,不要直接使用placement new,因为这毕竟不是用来构造对象的正式写法,而只不过是new operator的一个步骤而已,当我们使用new operator时,编译器会相应地自动生成调用placement new的代码,而不需要我们手动对其进行编写。


二、delete的浅析

在C++中,delete的使用和new的使用是相对应


• delete operator

delete operator,又称delete表达式(delete expression) ,它和new operator相对应,主要功能是用来释放动态开辟的内存空间的

语法:

语法1:delete 指针名 //释放指针所指的动态开辟的内存空间(存变量)
语法2:delete []指针名 //释放指针所指的动态开辟的内存空间(存数组)

示例:

string *name=new string("Tomwenxing");
delete name;//语法1的演示 int *data=new int[];
delete []data;//语法2的演示

事实上和new operator相似,delete operator在释放动态开辟的内存空间时,主要完成了两项工作:

1.调用析构函数,释放动态空间中存储的内容

2.释放动态空间(由operator delete来完成,很多编译其借助C语言中的free来实现)

 #include<iostream>
#include<string>
#include<new>
using namespace std;
class Student{
public:
Student(){
cout<<"调用默认构造函数"<<endl;
}
Student(string name){
cout<<"调用带参数的构造函数"<<endl;
Name=new string;
*Name=name;
}
~Student(){
cout<<"调用析构函数"<<endl;
delete Name;
}
private:
string *Name;
}; int main(){
Student *stu=new Student("Tomwenxing");
delete stu;
return ;
}

Question:delete operator为什么先调用析构函数然后才释放动态开辟的内存空间呢?

Answer:以上面的示例为例,当指向完语句Student *stu=new Student("Tomwenxing")之后,内存中的空间分配情况大致如下:

此时如果不先调用析构函数来释放构造函数中new operator开辟的内存空间,而是先释放main函数中new operator开辟的内存空间,则会导致内存泄漏(堆区中动态开辟的用来存储字符串“Tomwenxing”的内存空间无法释放,因为此时指向这个空间的指针Name所占据的内存空间已经被释放,系统将无法准确定位该内存空间)


• operator delete

delete operator的第二步(释放动态开辟的内存空间)是通过operator delete来实现的,它的声明通常如下:

void operator delete(void *p);

特别注意:

1.operator delete的返回值类型是void而不是void*,并且operator delete和operator delete[]均支持重载。

2.如果我们只打算处理原始的、为设置初始值的内存,这应该完全回避new operator和delete operator,改调用operator new取得内存并以operator delete释放内存

 void *buffer=operator new(*sizeof(char));
......
operator delete(buffer);

这组行为相当于在C++中调用malloc和free

3.很多编译器是通过free来实现operator delete的

C++:new&delete的更多相关文章

  1. SQL-W3School-基础:SQL DELETE 语句

    ylbtech-SQL-W3School-基础:SQL DELETE 语句 1.返回顶部 1. DELETE 语句 DELETE 语句用于删除表中的行. 语法 DELETE FROM 表名称 WHER ...

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

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

  3. SQL SERVER 2005删除维护作业报错:The DELETE statement conflicted with the REFERENCE constraint "FK_subplan_job_id"

    案例环境: 数据库版本: Microsoft SQL Server 2005 (Microsoft SQL Server 2005 - 9.00.5000.00 (X64) ) 案例介绍: 对一个数据 ...

  4. (转)iOS sqlite :truncate/delete/drop区分

    转自:http://blog.sina.com.cn/s/blog_6755689f0101fofb.html 相同点: 1.truncate和不带where子句的delete.以及drop都会删除表 ...

  5. Hibernate级联删除时:Cannot delete or update a parent row: a foreign key constraint fails异常

    在删除主表数据时,报了一个异常 Cannot delete or update a parent row: a foreign key constraint fails 原因是主表中还包含字表的数据, ...

  6. 微信SDK导入报错 Undefined symbols for architecture i386:"operator delete[](void*)", referenced from:

    异常信息: Undefined symbols for architecture i386:  "operator delete[](void*)", referenced fro ...

  7. 转载:指针delete后要设置为NULL

    本文来自:http://rpy000.blog.163.com/blog/static/196109536201292615547939/ 众所周知,最开始我们用new来创建一个指针,那么等我们用完它 ...

  8. C++基础学习7:new/delete操作符

    在C语言中,动态分配和释放内存的函数是malloc.calloc和free,而在C++语言中,new.new[].delete和delete[]操作符通常会被用来动态地分配内存和释放内存. 需要注意的 ...

  9. 创建包含CRUD操作的Web API接口5:实现Delete方法

    本节是前面四节的延续,在前面几节中我们创建了Web API并添加了必要的基础设施,实现了Get.Post.和Put方法.本节中,我们将介绍如何在Web API中实现Delete方法. 在RESTful ...

随机推荐

  1. UCOSii和Linux的区别和联系

    UCOSii和Linux的区别和联系 想通过UCOSii来理解Linux的系统架构,故参考一些资料,简单整理了一下UCOSii和Linux的区别和联系,以此来更好的学习Linux. 其具体对比如下: ...

  2. 解决:Cannot load ocl.dll library(error code 126). The ocil.dll library may be missing from the system

           因为这两天在做将springboot 项目使用的数据库MySQL转换为Oracle数据库,所以在网上查找相关资料后开始使用 Convert-Mysql-to-Oracle4.0做转换: ...

  3. React Webpack cookbook

    https://christianalfoni.github.io/react-webpack-cookbook/index.html https://fakefish.github.io/react ...

  4. PostgreSQL集群方案相关索引页

    磨砺技术珠矶,践行数据之道,追求卓越价值 返回顶级页:PostgreSQL索引页 本页记录所有本人所写的PostgreSQL的集群方案相关文摘和文章的链接: pgpool-II: 1 pgpool-I ...

  5. EnterpriseDb公司的Postgres Enterprise Manager 安装图解

    磨砺技术珠矶,践行数据之道,追求卓越价值 回到上一级页面: PostgreSQL基础知识与基本操作索引页     回到顶级页面:PostgreSQL索引页 [作者 高健@博客园  luckyjackg ...

  6. 【转】numpy教程

    [转载说明] 本来没有必要转载的,只是网上的版本排版不是太好,看的不舒服.所以转过来,重新排版,便于自己查看. 基础篇 NumPy的主要对象是同种元素的多维数组. 这是一个所有的元素都是一种类型.通过 ...

  7. PHP数据库的 增 删 查

    一.匹配数据库登录 步骤: 1.做一个普通的登录界面,注意提交方式为post. <!--登录界面--> <form action="chuli.php" meth ...

  8. js中哈希表的几种用法总结

    本篇文章只要是对js中哈希表的几种用法进行了总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助 1. <html> <head> <script type=" ...

  9. IIS7 增加JSON文件解析

    在MIME增加一个Json类型,在MIME增加一个配置如:添加---> 文件扩展名为 .JSON ,MIME类型为text/json(也有将application/x-javascript) 然 ...

  10. 遗留系统:IT攻城狮永远的痛

    我常常觉得我们非常幸运,我们现在所处的时代是一个令人振奋的时代,我们进入了软件工业时代.在这个时代里,我们进行软件开发已经不再是一个一个的小作坊,我们在进行着集团化的大规模开发.我们开发的软件不再是为 ...