Нужно ли перегрузить новый оператор размещения, когда мы перегружаем новый оператор?

У меня ниже фрагмент кода

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, если я не раскомментирую перегруженную операторную функцию нового размещения. Если я закомментирую нормально перегруженный новый, в этом случае он также работает нормально. Обязательна ли перегрузка размещения new при перегрузке обычного оператора new (если для этого класса необходимо использовать размещение new)

Код, связанный с удалением размещения, здесь не показан.

8
задан Bill the Lizard 18 September 2012 в 16:56
поделиться

3 ответа

Обычно нет, так как используется нечасто. Но это может быть необходимо, так как когда вы перегружаете operator new в классе, он скрывает все перегрузки глобального ::operator new.

Итак, если вы хотите использовать новое размещение для объектов этого класса, сделайте это; иначе не надо. То же самое касается ничего нового.

Если вы только что изменили схему распределения и удивлены тем, что кто-то где-то использует новое размещение за вашей спиной, это может быть чем-то, что нужно изучить, прежде чем применять этот лейкопластырь.

Если класс используется внутри контейнеров стандартной библиотеки, а не напрямую с new, пользовательская схема распределения должна определяться классом Allocator, а не перегрузкой. Распределитель по умолчанию std::allocator не учитывает перегруженные элементы operator new, но обходит их. Увидеть ниже.


Заявление об отказе от ответственности: перегрузки class-scope operator new в основном полезны для отладки, и даже в этом случае сложно получить надежно осмысленную семантику.Осторожно:

  • Вам также необходимо перегрузить оператор удаления. (Не сделано в примере в этом вопросе.)

  • Перегрузки будут обходить квалифицированный синтаксис ::new T. Вы не можете предотвратить такой обход. Именно так std::allocator распределяет ресурсы. Вы можете специализировать std::allocator для своих типов, но это уже какой-то путь в кроличью нору.

  • Для каждой перегрузки ::operator new, представленной любой библиотекой, включая каноническое размещение new из , вам придется рассмотреть, применимо ли это к вашему классу, и решить, следует ли добавить перегрузку или иным образом бороться с ошибкой неквалифицированных новых выражений.

  • Для каждого ::operator new, который вы внедряете в свой класс, вы должны предоставить соответствующее размещение члена operator delete с правильной семантикой. Это вызывается в случае выхода конструктора по исключению. Его отсутствие приведет к утечке памяти только при очень специфических обстоятельствах, возможно, в пуле с ограниченными ресурсами.

Таким образом, элемент оператор new является полной противоположностью защитного кодирования.

3
ответ дан 6 December 2019 в 00:04
поделиться

По умолчанию новый оператор размещения не существует для класса, поэтому при вызове new(p) Test(i); компилятор C++ не может найти определение закомментированного функцию в приведенном выше примере. Если вы раскомментируете оператор размещения, новый для вашего класса, и закомментируете «обычный», тогда будет использоваться «обычный» новый оператор по умолчанию, и ваш код будет скомпилирован.

1
ответ дан 6 December 2019 в 00:04
поделиться

реализации std::_Construct используют global новое размещение. Так что опасения по поводу совместимости с STL не должны вызывать беспокойства. Но беспокойство по поводу взлома существующего кода, который, возможно, был написан

новой ((void*)p) вещью;

вместо

::new ((void*)p) вещь;

, безусловно, верное замечание.

0
ответ дан 6 December 2019 в 00:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: