当我们超载new运算符时,是否有必要重载放置new运算符?

时间:2010-08-30 11:38:27

标签: c++

我有一段代码

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中编译,除非我取消注释重载的放置新操作符函数。 如果我注释掉正常重载的新内容,那么它也能正常工作。 当重载普通的新操作符时,是否需要重载新的必需项(如果需要为该类使用新的位置)

此处未显示展示位置删除相关代码。

3 个答案:

答案 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;

当然是一个有效的观点。