简体   繁体   English

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

[英]Is it necessary to overload placement new operator, when we overload new operator?

I have below piece of code 我有下面的代码

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);
}

Above piece of code does not compile in visual studio, unless i uncomment out the overloaded placement new operator function. 除非我取消注释重载的新操作符功能,否则以上代码无法在Visual Studio中编译。 If i comment out normal overloaded new, in that case also it works fine. 如果我注释掉正常的超载新的,在这种情况下也可以正常工作。 Is overloading of placement new mandatory when overloading normal new operator(If placement new need to be used for that class) 当重载普通的new运算符时是否强制重载新的位置(如果该类需要使用重载new)

Placement delete related code is not shown here. 此处没有显示与展示位置删除相关的代码。

Usually no, since it's not often used. 通常不,因为它不经常使用。 But it might be necessary, since when you overload operator new in a class, it hides all overloads of the global ::operator new . 但这可能是必要的,因为当您在类中重载operator new时,它将隐藏全局::operator new所有重载。

So, if you want to use placement new on objects of that class, do; 因此,如果要在该类的对象上使用new放置,请执行; otherwise don't. 否则不要。 Same goes for nothrow new. 这同样适用于nothrow新的。

If you've just changed the allocation scheme, and you're surprised that someone somewhere is using placement new behind your back, that might be something to investigate before applying this band-aid. 如果您刚刚更改了分配方案,并且感到惊讶的是某人在后面使用新的放置方式,那么在应用此创可贴之前可能需要进行调查。

If the class is used inside standard library containers, not directly with new , the custom allocation scheme should be defined by an Allocator class, not an overload. 如果该类在标准库容器中使用,而不是直接与new ,则自定义分配方案应由Allocator类定义,而不是重载。 The default allocator std::allocator does not respect member operator new overloads, but bypasses them. 默认分配器std::allocator不遵守成员operator new重载,而是绕过它们。 See below. 见下文。


Disclaimer : class-scope operator new overloads are mainly useful for debugging, and even then it's tricky to get reliably meaningful semantics. 免责声明 :类作用域operator new重载主要用于调试,即使那样,要获得可靠的有意义语义也很棘手。 Beware: 谨防:

  • You need to also overload operator delete . 您还需要重载operator delete (Not done in the example in this question.) (在此问题的示例中未完成。)

  • Overloads will be bypassed by the qualified syntax ::new T . 过载将被限定语法::new T绕过。 You cannot prevent such bypassing. 您不能阻止这种绕过。 This is the way that std::allocator<T> allocates things. 这就是std::allocator<T>分配事物的方式。 You can specialize std::allocator for your types, but that's some way into the rabbit-hole already. 您可以为您的类型专门设置std::allocator ,但这已经有些麻烦了。

  • For each ::operator new overload introduced by any library, including the canonical placement new from <new> , you will have to consider whether it applies to your class and decide whether to add an overload, or otherwise contend with the failure of unqualified new expressions. 对于任何库引入的每个::operator new重载,包括<new> new规范放置,您都必须考虑它是否适用于您的类,并决定是否添加重载,或者应对不合格new的失败。表达式。

  • For each ::operator new you adopt into your class, you must supply the corresponding member placement operator delete with correct semantics. 对于您在类中采用的每个::operator new ,必须提供具有正确语义的相应成员放置operator delete This is called in case the constructor exits by exception. 如果构造函数异常退出,则调用此方法。 Failing to have it would result in a memory leak only under very specific circumstances, in a possibly resource-constrained pool. 仅在非常特定的情况下,否则可能会导致资源泄漏,否则可能导致内存泄漏。

In summary, member operator new is the antithesis of defensive coding. 总而言之,成员operator new是防御性编码的对立面。

Placement new operator doesn't exist by default for a class so when you're making a call to new(p) Test(i); 默认情况下,类的Placement new运算符不存在,因此当您调用new(p) Test(i); C++ compiler can't find a definition of the commented function in the above example. 在以上示例中,C ++编译器找不到注释函数的定义。 If you uncomment the placement operator new for your class, and comment out the "normal" one then the default "normal" new operator will be used and your code will compile. 如果取消注释类的new放置运算符,并注释掉“ normal”一词,则将使用默认的“ normal” new运算符,并且代码将编译。

implementations of std::_Construct use the global placement new. std :: _ Construct的实现使用新的全局放置。 So concerns about STL compatability should not be concerns. 因此,不必担心STL兼容性。 But the concern about breaking existing code, that may have been written 但是对于破坏现有代码的担忧,可能已经写成

new ((void*)p) thing;

rather than 而不是

::new ((void*)p) thing;

is certainly a valid point. 当然是正确的一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM