先科普一下:

1. new的执行过程:

(1)通过operator new申请内存

(2)使用placement new调用构造函数(内置类型忽略此步)

(3)返回内存指针

2. new和malloc的比较:

(1)new失败时会调用new_handler处理函数,malloc不会,失败时返回NULL

(2)new能通过placement new自动调用对象的构造函数,malloc不会

(3)new出来的东西是带类型的,malloc是void*,需要强制转换

(4)new是C++运算符,malloc是C标准库函数

3. delete的执行过程:

(1)调用析构函数(内置类型忽略此步)

(2)释放内存

4.delete和free的比较

(1)delete能自动调用对象的析构函数,malloc不会

(2)delete是C++运算符,free是C标准库函数


new operator/delete operator就是new和delete操作符,而operator new/operator delete是函数。

new 运算符
(1)调用operator new分配足够的空间,并调用相关对象的构造函数
(2)不可以被重载

operator new
(1)只分配所要求的空间,不调用相关对象的构造函数。当无法满足所要求分配的空间时,则
        ->如果有new_handler,则调用new_handler,否则
        ->如果没要求不抛出异常(以nothrow参数表达),则执行bad_alloc异常,否则
        ->返回0
(2)可以被重载
(3)重载时,返回类型必须声明为void*
(4)重载时,第一个参数类型必须为表达要求分配空间的大小(字节),类型为size_t
(5)重载时,可以带其它参数

delete 与 delete operator类似

#include <iostream>
#include <string>
using namespace std; class X
{
public:
X() { cout<<"constructor of X"<<endl; }
~X() { cout<<"destructor of X"<<endl;} void* operator new(size_t size,string str)
{
cout<<"operator new size "<<size<<" with string "<<str<<endl;
return ::operator new(size);//调用全局的operator new申请空间
} void operator delete(void* pointee)
{
cout<<"operator delete"<<endl;
::operator delete(pointee);//调用全局的operator delete释放空间
}
private:
int num;
}; int main()
{
X *px = new("A new class") X;
delete px; return 0;
}

  注意::operator new是全局的函数,全局的这样的函数有三个,其中有一个就是placemet new,后面说。一般用户不会(虽然能)在全局重载operator new函数,而是在自定义的类中重载operator new函数。operator new都是申请一个对象的空间内存,所以调用的时候size_t省略,但是对于operator new[]这个函数,要明确的说明数组中对象的个数。


new和delete操作符我们应该都用过,它们是对堆中的内存进行申请和释放,而这两个都是不能被重载的。要实现不同的内存分配行为,需要重载operator new和operator delete,而不是new和delete。

operator new就像operator+一样,是可以重载的。但是不能在全局对原型为void operator new(size_t size)这个原型进行重载,一般只能在类中进行重载。如果类中没有重载operator new,那么调用的就是全局的::operator new来完成堆的分配。同理,operator new[]、operator delete、operator delete[]也是可以重载的。

至于placement new,只是operator new的一个重载的版本,只是我们很少用到它。如果你想在已经分配的内存中创建一个对象,使用new时行不通的。也就是说placement new允许你在一个已经分配好的内存中(栈或者堆中)构造一个新的对象。原型中void*p实际上就是指向一个已经分配好的内存缓冲区的的首地址。

我们知道使用new操作符分配内存需要在堆中查找足够大的剩余空间,这个操作速度是很慢的,而且有可能出现无法分配内存的异常(空间不够)。placement new就可以解决这个问题。我们构造对象都是在一个预先准备好了的内存缓冲区中进行,不需要查找内存,内存分配的时间是常数。而且不会出现在程序运行中途出现内存不足的异常。所以,placement new非常适合那些对时间要求比较高,长时间运行不希望被打断的应用程序。 placement new使用方法如下:

1. 缓冲区提前分配,可以使用堆的空间,也可以使用栈的空间。所以分配方式有如下两种:
class MyClass {…};
char *buf = new char[N * sizeof(MyClass)];
char buf[N * sizeof(MyClass)]; 2. 对象的构造
MyClass * pClass = new(buf) MyClass; //使用placement new 3. 对象的销毁
一旦这个对象使用完毕,你必须显式的调用类的析构函数进行销毁对象。但此时内存空间不会被释放,以便其他的对象的构造。
pClass->~MyClass(); 4. 内存的释放
如果缓冲区在堆中,那么调用delete[] buf 进行内存的释放。如果在栈中,那么在其作用域内有效,跳出作用域,内存自动释放。 补充说明:
在C++标准中,对于placement operator new []有如下的说明:
placement operator new[] needs implementation-defined amount of additional storage to save a size of array。
所以我们必须申请比原始对象大小多出sizeof(int)个字节来存放对象的个数,或者说数组的大小。
使用方法第二步中的new才是使用placement new,其实是没有申请内存的,只是调用了构造函数。
返回一个指向已经分配好的内存的一个指针,所以对象销毁的时候不需要调用delete释放空间,但必须调用析构函数销毁对象。
所以对于placement new用于对象数组的时候:
char *buf=new char[N*sizeof(MyClass)+sizeof(int)];
char buf[N*sizeof(MyClass)+sizeof(int)];
MyClass * pClass=new(buf) MyClass[N]; //使用placement new[]

前面说到了全局那里有三个operator new函数,下面看看:

operator new分为三种形式(前2种不调用构造函数,这点区别于new operator):

1: void* operator new (std::size_t size) throw (std::bad_alloc);
2: void* operator new (std::size_t size, const std::nothrow_t & nothrow_constant) throw();
3: void* operator new (std::size_t size, void* ptr) throw(); 

第一种分配size个字节的存储空间,并进行对象类型进行内存对齐。如果成功,返回一个非空的指针指向首地址。失败抛出bad_alloc异常。

第二种在分配失败时不抛出异常,它返回一个NULL指针。

第三种是placement new版本。它不分配内存,调用合适的构造函数在ptr所指的地方构造一个对象,之后返回实参指针ptr。

三种版本的operator new 定义在全局命名空间,不在std中。第一、第二个版本C++默认在每个编译单元中声明,不需要#include <new>头文件。第一、第二个版本可以被用户更换和重载(一般在类中重载),定义自己的版本,第三种placement new不可重载。

// operator new example
#include <iostream>
#include <new>
using namespace std; struct myclass {myclass() {cout <<"myclass constructed\n";}}; int main ()
{
int * p1 = new int;
// same as:
// int * p1 = (int*) operator new (sizeof(int)); int * p2 = new (nothrow) int;
// same as:
// int * p2 = (int*) operator new (sizeof(int),nothrow); myclass * p3 = (myclass*) operator new (sizeof(myclass));
// (!) not the same as:
// myclass * p3 = new myclass;
// (constructor not called by function call, even for non-POD types) new (p3) myclass; // calls constructor
// same as:
// operator new (sizeof(myclass),p3) return 0;
}
//结果输出:myclass constructed

  

[C++空间分配]new运算符、operator new、placement new的区别于联系的更多相关文章

  1. operator new,new operator,placement new的区别

    原文地址:http://www.cnblogs.com/jamesmile/archive/2010/04/17/1714311.html,在此感谢 C++中的operator new与new ope ...

  2. Python第二天 变量 运算符与表达式 input()与raw_input()区别 字符编码 python转义符 字符串格式化 format函数字符串格式化 帮助

    Python第二天  变量  运算符与表达式  input()与raw_input()区别  字符编码  python转义符  字符串格式化  format函数字符串格式化  帮助 目录 Pychar ...

  3. C++内存管理(new operator/operator new/operator delete/placement new)

    new operator 我们平时使用的new是new操作符(new operator),就像sizeof一样是语言内置的,不能改变它的含义,功能也是一样的 比如: string *ps = new ...

  4. Swift学习(一):自定义运算符 operator

    自定义运算符仅能包含这些字符: / = - + * % < >!& | ^.~ 运算符位置: 前置运算符 prefix 中间运算符 infix 后置运算符 postfix 运算符其 ...

  5. 【转】C++易混知识点3. New Operator, Operator New, Placement New 实例分析,比较区别

    我们知道,C++中引入了New 这个内置符号,很大方便了指针的使用,程序员不必关注与这块堆上新分配的内存是如何来的,如何初始化的,然后如何转换为我们想要的类型指针的.现在,我们重点来分析下这个NEW内 ...

  6. c++中new/operator new/placement new

    1. new/delete c++中的new(和对应的delete)是对堆内存进行申请和释放,且两个都不能被重载. 2. operator new/operator delete c++中如果想要实现 ...

  7. 重载运算符-operator

    先看段代码: struct node { friend bool operator< (node n1, node n2){ // 优先取最小的,它与下面的 // 是等价的 return n1. ...

  8. 操作符(运算符)重载 或者叫 二元运算符 operator + 与 转换式操作符 implicit operator explicit operator

    static void Main(string[] args) { rational r1 = new rational(5); rational r2 = new rational(51); rat ...

  9. 运算符 Operator 及优先级

    算数运算符 + - * / ** % /表示自然除,结果是浮点数.//为整除.python2.x版本/和//都是整除. 位运算符 & | ~ ^ << >> <& ...

随机推荐

  1. 一个loader加载多个swf

    var _swfLoader:Loader; var _swfRequest:URLRequest; var _swfPathArr:Array = new Array("00.swf&qu ...

  2. 【线段树求逆序数】【HDU1394】Minimum Inversion Number

    题目大意: 随机给你全排列中的一个,但不断的把第一个数丢到最后去,重复N次,形成了N个排列,问你这N个排列中逆序数最小为多少 做法: 逆序数裸的是N^2 利用线段树可以降到NlogN 具体方法是插入一 ...

  3. 【DFS+小操作判重】【HDU2610+HDU2611】Sequence

    题意 2610 按照长度优先 位置次之 输出所有不递减序列 2611 按照长度优先 大小次之 输出所有不递减序列 题解不写了 来源于http://www.cnblogs.com/wally/archi ...

  4. js实现form表单提交,图片预览功能

    代码如下 <html> <head> <meta http-equiv="Content-Type" content="text/html; ...

  5. Web--->>>Cookie与Session

    1.cookie 1.cookie是存在客户端(浏览器)的进程内存中和客户端所在的机器硬盘上 2.cookie只能能够存储少量文本,大概4K大小 3.cookie是不能在不同浏览器之间共享 3.创建c ...

  6. 几个Python oj的网站

    http://www.rqnoj.cn/ http://www.pythontip.com/

  7. Javascript Number类型常见迷惑点

    1:NaN(Not a Number) 表示一个本来要返回数值的操作数没有返回数值的情况.在ECMAscript中,任何数除以0会返回NaN[ps:实际上只有0/0会返回NaN],正(负)数除以0会返 ...

  8. Ecside基于数据库的过滤、分页、排序

    首先ecside展现列表.排序.过滤(该三种操作以下简称为 RSF )的实现原理完全和原版EC一样, 如果您对原版EC的retrieveRowsCallback.sortRowsCallback.fi ...

  9. Python入门之中文乱码

    python入门编码: Python 文件中如果未指定编码,有中文代码时候,在执行过程会出现报错: File "test.py", line 2 SyntaxError: Non- ...

  10. Get a handle on PHP Handlers

    PHP Handlers? mod_php? FPM? How do we make sense of the inner workings of PHP outside of our lines o ...