C++ 标准是否保证动态分配是用 new 完成的?
Does the C++ standard guarantee that dynamic allocations are done with new?
简单的学习题。 C++ 标准中是否指定了 std 类 分配内存的方式?我假设在内部,所有分配都在某个时候转发到 new
/ new[]
。我对容器、std::function 和 lambda 进行的分配特别感兴趣。
标准库容器
标准库容器采用分配器模板参数,用于控制内存的分配方式。默认情况下,他们使用 std::allocator<T>
. std::allocator<T>
has a member function std::allocator<T>::allocate()
即:
Allocates n * sizeof(T)
bytes of uninitialized storage by calling ::operator new(std::size_t)
同样,有一个 std::allocator<T>::deallocate()
函数调用 operator delete(void *)
。
std::function
std::function
有 several constructors,其中一些允许您指定分配器对象以用于其内部分配。如果您不指定一个,那么它将使用 std::allocator
.
Lambdas
我不确定您希望使用 lambda 完成哪些分配。当您声明一个 lambda 时,编译器会在幕后合成一个未命名的仿函数类型,在其 operator()
中实现该 lambda。如果您从本地范围捕获任何变量,这些变量将简单地成为该类型定义的一部分,从而增加 lambda 类型的大小,但不需要任何动态分配;捕获的变量只是 lambda 未命名类型的成员。如果您要将 lambda 分配给 std::function
之类的东西,那么 std::function
可以进行动态分配以适应 lambda 增加的大小。
标准库中的 类 通常是模板,可以使用特定的分配器来满足特殊需要。默认情况下,他们使用标准分配器 (std::allocator
),它使用 operator new
和 operator delete
:
20.7.9.1 allocator members [allocator.members]
...
pointer allocate(size_type n, allocator<void>::const_pointer hint = 0);
...
Remark: the storage is obtained by calling ::operator new(std::size_t) (18.6.1), but it is unspecified
when or how often this function is called...
void deallocate(pointer p, size_type n);
...
Remarks: Uses ::operator delete(void*, std::size_t) (18.6.1), but it is unspecified when this
function is called.
由于性能原因,调用运算符 new 和 delete 时未指定的事实允许实现缓存未使用的内存块。
标准容器接受作为分配器的模板化参数。默认情况下,每个标准容器的分配器都是 std::allocator<T>
类型(例如 std::vector<T>
的默认分配器是 std::allocator<T>
类型)。 std::allocator
使用函数 ::operator new(size_t)
分配原始内存。
典型的新表达式(例如 new Type
形式)的部分工作是调用函数 ::operator new(size_t)
。但是,不需要默认分配器来使用这样的新表达式。
分配器接口的一部分是提供一个成员函数construct(pointer p, const_reference val)
。 std::allocate<T>
returns new((void *)p) T(val)
的成员函数(有时被描述为放置新表达式)。
不要求非默认分配器(例如程序员提供的分配器类型而不是默认分配器)使用 ::operator new()
或新表达式。
简单的学习题。 C++ 标准中是否指定了 std 类 分配内存的方式?我假设在内部,所有分配都在某个时候转发到 new
/ new[]
。我对容器、std::function 和 lambda 进行的分配特别感兴趣。
标准库容器
标准库容器采用分配器模板参数,用于控制内存的分配方式。默认情况下,他们使用 std::allocator<T>
. std::allocator<T>
has a member function std::allocator<T>::allocate()
即:
Allocates
n * sizeof(T)
bytes of uninitialized storage by calling::operator new(std::size_t)
同样,有一个 std::allocator<T>::deallocate()
函数调用 operator delete(void *)
。
std::function
std::function
有 several constructors,其中一些允许您指定分配器对象以用于其内部分配。如果您不指定一个,那么它将使用 std::allocator
.
Lambdas
我不确定您希望使用 lambda 完成哪些分配。当您声明一个 lambda 时,编译器会在幕后合成一个未命名的仿函数类型,在其 operator()
中实现该 lambda。如果您从本地范围捕获任何变量,这些变量将简单地成为该类型定义的一部分,从而增加 lambda 类型的大小,但不需要任何动态分配;捕获的变量只是 lambda 未命名类型的成员。如果您要将 lambda 分配给 std::function
之类的东西,那么 std::function
可以进行动态分配以适应 lambda 增加的大小。
标准库中的 类 通常是模板,可以使用特定的分配器来满足特殊需要。默认情况下,他们使用标准分配器 (std::allocator
),它使用 operator new
和 operator delete
:
20.7.9.1 allocator members [allocator.members]
...pointer allocate(size_type n, allocator<void>::const_pointer hint = 0);
...
Remark: the storage is obtained by calling ::operator new(std::size_t) (18.6.1), but it is unspecified when or how often this function is called...void deallocate(pointer p, size_type n);
...
Remarks: Uses ::operator delete(void*, std::size_t) (18.6.1), but it is unspecified when this function is called.
由于性能原因,调用运算符 new 和 delete 时未指定的事实允许实现缓存未使用的内存块。
标准容器接受作为分配器的模板化参数。默认情况下,每个标准容器的分配器都是 std::allocator<T>
类型(例如 std::vector<T>
的默认分配器是 std::allocator<T>
类型)。 std::allocator
使用函数 ::operator new(size_t)
分配原始内存。
典型的新表达式(例如 new Type
形式)的部分工作是调用函数 ::operator new(size_t)
。但是,不需要默认分配器来使用这样的新表达式。
分配器接口的一部分是提供一个成员函数construct(pointer p, const_reference val)
。 std::allocate<T>
returns new((void *)p) T(val)
的成员函数(有时被描述为放置新表达式)。
不要求非默认分配器(例如程序员提供的分配器类型而不是默认分配器)使用 ::operator new()
或新表达式。