我看过很多关于 C++ 内存分配的帖子,关于“new operator”与“operator new”的问题,关于new int(100) vs new int[100] 的问题,关于内存初始化的问题......我认为应该有一个一劳永逸地总结一切的答案,我选择这个问题来写这个总结。它是关于动态内存分配的,ie 在运行时在堆上分配。我还提供了一个summary implementation(公共域)。
C 与 C++
动态内存分配的主要函数:
- 在C(标题
<cstdlib>)中,我们主要有malloc和calloc和free。我不会谈论realloc。
- 在 C++ 中(标题
<new>),我们有:
- 带有初始化参数的模板单对象分配:
-
new T( args )
-
new (std::nothrow) T( args )
delete ( T* )
- 具有默认初始化的模板多对象分配:
new T[ size_t ]
new (std::nothrow) T[ size_t ]
delete[] ( T* )
- 没有为单个或多个对象分配的模板内存初始化:
-
new (void*) T( args )
new (void*) T[ size_t ]
- 内部新表达式:
- 原始内存分配
::operator new( size_t );
- 原始内存分配无异常
::operator new( size_t, std::nothrow );
- 未分配的原始内存初始化
::operator new( size_t, ptr )。
请查看this post 进行简明比较。
旧版 C 动态分配
要点:完全类型擦除(void* 指针),因此无构造/破坏,以字节为单位指定大小(通常使用sizeof)。
malloc( size_t ) 根本不初始化内存(原始内存包含垃圾,总是在使用前手动初始化)。 calloc( size_t, size_t ) 将所有位初始化为 0(开销很小,但对 POD 数字类型很有用)。任何分配的内存都应使用free ONLY 释放。
类实例的构造/销毁应该手动完成 在使用/在内存释放之前。
C++ 动态分配
要点:由于相似的语法做不同的事情而令人困惑,all delete-statements 调用析构函数,all delete-statements 采用全类型指针,一些 new-statements 返回全类型指针,一些 new-statements 调用一些构造函数。
警告:如下所示,new 可以是关键字或函数。为了avoid confusions,最好不要谈论“新操作员”和/或“新操作员”。我将任何包含new 作为函数或关键字的有效语句称为“new-statements”。人们还谈论“new-expressions”,其中new 是关键字而不是函数。
原始内存分配(无初始化)
不要自己使用它。这是由 new-expressions 内部使用的(见下文)。
这些分配不初始化内存,特别是,它们不在分配的对象上调用默认构造函数。因此,您必须手动初始化所有元素,然后再使用delete 或delete[] 释放分配。
注意:我怎么强调都不应该让你自己使用它。但是,如果您应该使用它,请确保在此类分配上调用delete 或delete[] 时传递指向void 的指针而不是类型化指针(始终在手动初始化之后)。我亲身经历过使用某些编译器的非 POD 类型的运行时错误(可能是我的错误)。
原始内存初始化(无分配)
不要自己使用它。这是由 new-expressions 内部使用的(见下文)。
在下文中,我假设void *ptr = ::operator new( n*sizeof(T) ) 用于某些类型T 和大小n。
然后::operator new( n*sizeof(T), (T*) ptr )使用默认构造函数T::T()从ptr开始初始化n类型的元素T。这里没有没有分配,只是使用默认构造函数进行初始化。
单对象分配和初始化
-
new T( args ) 使用构造函数T::T( args ) 为T 类型的单个对象分配和内存。默认构造函数不会被调用除非 参数被省略(即new T() 甚至new T)。失败时抛出异常 std::bad_alloc。
- 与
new (std::nothrow) T( args ) 相同,只是在失败时返回NULL。
- 使用
delete调用析构函数T::~T(),释放对应的内存。
多对象分配和初始化
-
new T[n] 使用默认构造函数为T 类型的n 对象分配和内存。失败时抛出异常 std::bad_alloc。
- 与
new (std::nothrow) T[n] 相同,但在失败时返回NULL。
- 使用
delete[]为每个元素调用析构函数T::~T()并释放相应的内存。
内存初始化(又名“新放置”)
这里没有分配。不管如何分配:
-
new (ptr) T(args) 在存储在 ptr 的内存上调用构造函数 T::T(args)。除非省略参数,否则不会调用默认构造函数。
-
new (ptr) T[n] 在 n 类型的 T 对象上调用默认构造函数 T::T(),该对象从 ptr 存储到 ptr+n(即 n*sizeof(T) 字节)。
相关帖子