CPP之内存分配

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(2); // 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 + 1, 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 来实现的

posted @ 2014-10-03 21:49  Acjx  阅读(1677)  评论(0编辑  收藏  举报