我有一段代码
class Test
{
public:
Test(){}
Test(int i) {}
void* operator new (size_t size)
{
void *p = malloc(size);
return p;
}
//void* operator new (size_t size, Test *p)
//{
// return p;
//}
};
int main() {
Test *p = new Test;
int i = 10;
new(p) Test(i);
}
上面的代码片段不能在visual studio中编译,除非我取消注释重载的放置新操作符函数。 如果我注释掉正常重载的新内容,那么它也能正常工作。 当重载普通的新操作符时,是否需要重载新的必需项(如果需要为该类使用新的位置)
此处未显示展示位置删除相关代码。
答案 0 :(得分:3)
通常不会,因为它不经常使用。但它可能是必要的,因为当你在类中重载operator new
时,它会隐藏全局::operator new
的所有重载。
所以,如果你想在该类的对象上使用placement new,那么;否则不要。同样适用于nothrow
new。
如果您刚刚更改了分配方案,并且您感到惊讶的是某个地方某人正在使用背后的新位置,那么在应用此创可贴之前可能需要进行调查。
如果在标准库容器内使用该类,而不是直接使用new
,则自定义分配方案应由Allocator类定义,而不是过载。默认分配器std::allocator
不尊重成员operator new
重载,但会绕过它们。见下文。
免责声明:类范围operator new
重载主要用于调试,即使这样,获得可靠有意义的语义也很棘手。请注意:
您还需要重载operator delete
。 (在这个问题的例子中没有完成。)
过载将被限定语法::new T
绕过。你无法阻止这种绕过。这是std::allocator<T>
分配事物的方式。您可以为您的类型专门设置std::allocator
,但这已经进入了兔子洞。
对于任何库引入的每个::operator new
重载,包括来自<new>
的规范展示位置,您必须考虑它是否适用于您的类并决定是否添加重载,或以其他方式应对不合格的new
表达式的失败。
对于您在课程中采用的每个::operator new
,您必须提供具有正确语义的相应成员展示位置operator delete
。如果构造函数以异常退出,则调用此方法。如果没有它,只会在非常特殊的情况下,在可能受资源限制的池中导致内存泄漏。
总之,成员operator new
是防御性编码的对立面。
答案 1 :(得分:1)
默认情况下,对于类,不存在Placement new运算符,因此当您调用new(p) Test(i);
时,C ++编译器无法在上面的示例中找到注释函数的定义。如果取消注释类的新操作符,并注释掉“普通”操作符,则将使用默认的“普通”新操作符,并编译代码。
答案 2 :(得分:0)
std :: _ Construct的实现使用全局贴图新建。所以对STL兼容性的担忧不应该是问题。但是关于打破现有代码的担忧,可能已经写好了
new ((void*)p) thing;
而不是
::new ((void*)p) thing;
当然是一个有效的观点。