new & delete expression

1. Introduction

A new expression allocates and constructs an object of a specified type.

A new[] expression allocates and constructs an array of objects.

These expressions use the corresponding version of the library operator new functions to allocate raw memory in which the expression constructs an object or array of the specified type.

1. new 表达式分配和构造特定类型的对象。

2. new[] 表达式分配和构造对象数组。

3. 这些表达式使用库函数 operator new 的对应版本分配原始内存,并在该内存中构造特定类型的对象或数组。

A delete expression destroys a dynamically allocated object of a specified type and frees the memory used by that object.

A delete[] expression destroys the elements of a dynamically allocated array of a specified type and frees the memory used by the array.

These expressions use the corresponding version of the library or class-specific operator delete functions to free raw memory that held the object or array.

1. delete 表达式销毁特定类型的动态分配对象,并释放该对象所用的内存。

2. delete[] 表达式销毁特定类型动态分配数组的元素,并释放该数组所使用的内存。

3. 这些表达式使用库函数或类特定的 operator delete 函数的对应版本来释放保存对象或数组的原始内存。

2. How to work?

我们来看看 newdelete 表达式是如何工作的。例如,使用如下 new 表达式:

// new expression

string * sp = new string("initialized");

实际上发生了以下步骤:

首先,该表达式调用名为 operator new 的标准库函数,分配足够大的原始的未类型化的内存,以保存指定类型的一个对象;

接下来,运行该类型的一个构造函数,用指定初始化式构造对象;

最后,返回指向新分配并构造的对象的指针。

当使用如下 delete 表达式时:

delete sp;

将会删除堆上分配的对象,发生以下两个步骤:

首先,对 sp 指向的对象运行适当的析构函数;

然后,通过调用名为 operator delete 的标准库函数释放该对象所用内存。

operator new and operator delete Functions

1. The operator new and operator delete Interface

operator newoperator delete 函数有两个重载版本(一个抛异常,一个不抛异常),每个版本支持相关的 new 表达式和 delete 表达式:

void *operator new(size_t);        // allocate an object

void *operator new[](size_t);      // allocate an array

void *operator delete(void*);      // free an object

void *operator delete[](void*);    // free an array

虽然 operator newoperator delete 函数的设计意图是供 new 表达式使用,但它们也是标准库中的可用函数。我们可以使用它们来获得未构造的原始内存,它们有点类似 allocate 类的 allocatordeallocate 成员。

2. allocator and deallocate

std::allocator::allocate

pointer allocate (size_type n, allocator<void>::const_pointer hint=0);

Allocate block of storage

Attempts to allocate a block of storage with a size large enough to contain n elements of member type value_type (an alias of the allocator's template parameter), and returns a pointer to the first element.
The storage is aligned appropriately for objects of type value_type, but they are not constructed.
In the standard default allocator, the block of storage is allocated using ::operator new one or more times, and throws bad_alloc if it cannot allocate the total amount of storage requested.

分配原始内存空间,参数 n 填要分配的元素的个数,返回值是指向新分配的对象的指针。

Parameters

n Number of elements (each of size sizeof(value_type)) to be allocated.
        The member type size_type is an alias of size_t (in the standard default allocator) size_t is an unsigned integral
type.  hintEither 0 or a value previously obtained by another call to allocate and not yet freed with deallocate.
        When it is not 0, this value may be used as a hint to improve performance by allocating the new block near the one specified. The address of an adjacent element is often a good choice.(hint如果不是默认值0,可以填写之前 allocate 返回的指针,这可以在一定程度上提高性能)

Return value

A pointer to the initial element in the block of storage.

pointer and const_pointer are member types (defined as aliases of T* and const T* respectively in std::allocator<T>).

The standard default allocator throws bad_alloc if it cannot allocate the requested amount of storage.

std::allocator::deallocate

void deallocate (pointer p, size_type n);

Release block of storage

Releases a block of storage previously allocated with member allocate and not yet released.
The elements in the array are not destroyed by a call to this member function.
In the default allocator, the block of storage is at some point deallocated using ::operator delete (either during the function call, or later).

回收 p 指向的“可容纳 n 个元素”的内存空间

3. Placement new Expressions

1. 标准库函数 operator newoperator deleteallocatorallocatedeallocate 成员的低级版本,它们都分配但不初始化内存。

2. allocator 的成员 construct(执行对象的构造函数)destroy(执行对象的析构函数) 也有两个低级选择,这些成员在由 allocator 对象分配的空间中初始化和销毁对象。

3. 类似于 construct 成员,有第三种 new 表达式,称为定位 new定位 new 表达式在已分配的原始内存中初始化一个对象,它与 new 的其他版本的不同之处在于,它不分配内存。相反,它接受指向已分配但未构造内存的指针,并在该内存中初始化一个对象。实际上,定位 new 表达式使我们能够在特定的、预分配的内存地址构造一个对象。

operator new

throwing (1)

void* operator new (std::size_t size) throw (std::bad_alloc);

nothrow (2)

void* operator new (std::size_t size, const std::nothrow_t& nothrow_value) throw();

placement (3)

void* operator new (std::size_t size, void* ptr) throw();
其中第三种形式即为定位 new。

定位 new 表达式的形式是:

 new (place_address) type
new (place_address) type (initializer-list)
返回值:place_address

其中 place_address 必须是一个指针,而 initializer-list 提供了(可能为空的)初始化列表,以便在构造新分配的对象时使用。

定位 new 表达式比 allocator 类的 construct 成员更灵活。定位 new 表达式初始化一个对象的时候,它可以使用任何构造函数,并直接建立对象。construct 函数总是使用拷贝构造函数。

例如,可以用下面两种方式之一,从一对迭代器初始化一个已分配但未构造的 string 对象:

     allocator<string> alloc;
     
string *sp = alloc.allocate(); // allocate space to hold 2 strings
     
// two ways to construct a string from a pair of iterators
new (sp) string(b, e); // construct directly in place
alloc.construct(sp + , string(b, e)); // build and copy a temporary

定位 new 表达式使用了接受一对迭代器的 string 构造函数,在 sp 指向的空间直接构造 string 对象。而当调用 construct 函数的时候,必须首先从迭代器构造一个 string 对象(临时对象),以获得传递给 constructstring 对象,然后,该函数使用 string 的拷贝构造函数,将匿名临时 string 对象复制到 sp 指向的对象中。

通常,这些区别是无关紧要的:例如对于值型类而言,在适当的位置直接构造对象与构造临时对象并进行复制之间没有太大差别,并且性能差别也微乎其微。

但对某些类而言,使用拷贝构造函数是不可能的(因为复制构造函数是私有的),或者是应该避免的,在这种情况下,也许有必要使用定位 new 表达式来直接构造对象。

小结

1.

C++中的new运算符,具体工作流程如下:

1.调用标准库函数operator new申请原始内存

2.调用place new表达式,执行类的构造函数

3.返回内存地址

而delete操作符的工作是:

1.调用对象的析构函数

2.调用标准库函数operator delete释放内存

2.

分配原始内存的三种手段:

1. 使用malloc

2. 使用operator new

3. allocator的allocate函数

这三者从上到下,是一个由低级到高级的过程。

实际上标准库函数 allocate 就是通过标准库函数 operator new 实现,而 operator new 通常也是通过 malloc 来实现。

执行构造函数,有两种手段:

1. 使用placement new运算符

2. 使用allocator的construct函数

实际上标准库函数 construct 的内部就是通过 placement new 来实现的

CPP之内存分配的更多相关文章

  1. C/C++内存分配

    一.      预备知识—程序的内存分配: 一个由C/C++编译的程序占用的内存分为以下几个部分:1.栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结 ...

  2. c++中函数中变量内存分配以及返回指针、引用类型的思考

    众所周知,我们在编程的时候经常会在函数中声明局部变量(包括普通类型的变量.指针.引用等等). 同时,为了满足程序功能的需要,函数的返回值也经常是指针类型或是引用类型,而这返回的指针或是引用也经常指向函 ...

  3. C++内存分配及变长数组的动态分配

    //------------------------------------------------------------------------------------------------ 第 ...

  4. 源码分析:Java对象的内存分配

    Java对象的分配,根据其过程,将其分为快速分配和慢速分配两种形式,其中快速分配使用无锁的指针碰撞技术在新生代的Eden区上进行分配,而慢速分配根据堆的实现方式.GC的实现方式.代的实现方式不同而具有 ...

  5. C语言中的内存分配与释放

    C语言中的内存分配与释放 对C语言一直都是抱着学习的态度,很多都不懂,今天突然被问道C语言的内存分配问题,说了一些自己知道的,但感觉回答的并不完善,所以才有这篇笔记,总结一下C语言中内存分配的主要内容 ...

  6. java\c程序的内存分配

    JAVA 文件编译执行与虚拟机(JVM)介绍 Java 虚拟机(JVM)是可运行Java代码的假想计算机.只要根据JVM规格描述将解释器移植到特定的计算机上,就能保证经过编译的任何Java代码能够在该 ...

  7. 【转载】C内存分配

    一.预备知识—程序的内存分配  一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. ...

  8. 转:c++内存分配

    第一篇: http://my.oschina.net/pollybl1255/blog/140323 BSS段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS ...

  9. 程序的内存分配 C\C++

    原文:http://blog.csdn.net/oohaha_123/article/details/24460425 程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 1.栈区( ...

随机推荐

  1. C++获取当前执行程序文件所在的全路径

  2. Source Code Pro 编程字体

    Source Code Pro :是 Adobe 公司号称最佳的编程字体,而且还是开源的 它非常适合用于阅读代码,支持 Linux.Mac OS X 和 Windows 等操作系统,而且无论商业或个人 ...

  3. Http的那些事: Content-Type

    Content-Type 无疑是http中一个非常重要的属性了, request 中可以存在, 也可以不存在( request的Content-Type 默认是 */*, 实际上呢, 如果不存在Con ...

  4. Mysql 日期加减

    mysql表中有一些字段是显示日期的.因为各种需要,需要将它时间往后调整1年. mysql 日期增加一年的更新语句更新的语句如下:     UPDATE table SET date = DATE_A ...

  5. Eclipse 中Git的使用及如何解决冲突

    1. 如何导入已有Git项目 1.1 File——>import… 出现以下界面 1.2 找到Git,然后双击‘Project from Git.或者点击next 1.3 双击Clone URI ...

  6. 深入理解Java虚拟机之Java内存区域随笔

    1.java内存区域与内存溢出异常 Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域:1.程序计数器,2.栈(虚拟机栈和本地方法栈 ),3.堆,4.方法区(包含 ...

  7. 【FZSZ2017暑假提高组Day1】最大矩形

    [问题描述] 现在有n个宽度为1的矩形按如下图(左边的)所示的方式排在了一起: 用肉眼容易看出,在左图内部面积最大的矩形如右图绿色部分所标注. 现在我们考虑将其中一些宽度为1的矩形取出,按照原顺序再次 ...

  8. 面向对象的css less 和sass

    Css 初始化   reset.css      或者  normalise .   Near.css兼容IE6以及现代浏览器. Oocss  也就是面向对象的css         面向对象是将cs ...

  9. mongodb文件损坏的恢复--无可恢复数据

    1.mongodb 启动异常error code 100,检查日志,数据文件损坏 2 检查collection-15-6548623434943640018.wt 可恢复数据,为空,不存在恢复的数据 ...

  10. javaMail实现收发邮件(二)

    JavaMail API常用类 JavaMail API使用javax.mail.Message类来表示一封邮件,Message类是一个抽象类,所以我们需要使用其子类javax.mail.intern ...