非标准库放置new调用用户定义的运算符new:
class T {};
void* operator new(std::size_t s, T*) {
return new char[s];
}
int main() {
T* t;
new(t) T(); // calls operator new above
return 0;
}
但是,如果我没有错,标准展示位置new不会调用默认运算符new。这种分离允许标准分配器使用allocate()
中的new new来获取内存和placement new来初始化它,使用std :: initialize_fill()或construct()
现在我不明白当使用非标准贴图new时,如何将分配与自定义分配器中的初始化分开,因为非标准贴图new总是调用用户定义的operator new。应该总是强制在任何分配器中使用带有static_cast的标准placement new吗?
答案 0 :(得分:2)
据我所知,你在某种程度上混淆了operator new()
和新运算符:它们有不同的用途,尽管它们密切相关(Scott Meyers有一个关于此的项目)在有效的C ++中,如果正确回忆;或者,至少,他在早期版本中有一个项目,因为我现在看不到它):
operator new()
的目的是让内存可用。通常这相当于从某个地方分配内存,但在使用placement new的特殊情况下,它实际上除了返回其参数之外什么也没做。operator new()
包含两个步骤:
operator new()
也就是说,请注意,某个程序不允许替换运算符new
和delete
的展示位置版本!只允许替换用于实际内存分配的8个运算符(即operator new(size_t)
,operator delete(void*)
,相应的数组数组版本以及它们的std::nothrow_t
版本。有关更多详细信息,请参见17.6.4.6 [replacement.functions]。 placemement版本实际上是通过他们的地址参数和(operator delete()
来满足存在,以防在构造对象期间抛出异常)。
分配器的allocate()
成员意味着实际提供内存,例如通过调用malloc(n)
,operator new(n)
(但不是按new char[n]
),mmap()
页面等,这并不意味着实际构建任何内容对象(参见17.6.3.5 [allocator.requirements],特别是表28)。实际上构造对象是分配器的construct()
成员的目的。事实上,这个函数基本上需要调用placement new:
template <typename... A>
void allocator::construct(void* address, A&&... args) {
new(address) T(std::forward<A>(args)...);
}
(假设allocator
负责分配T
类型的对象。
在任何情况下,所记录的分配函数(malloc()
,operator new()
)都不会调用任何其他函数。它们可以在内部以通用函数的方式实现(可能就是这种情况)但您可以在自己的分配函数中调用它们。当然,如果您使用自己的版本替换运算符,则不会调用标准库提供的版本。