У меня ниже фрагмент кода
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)
Код, связанный с удалением размещения, здесь не показан.
Обычно нет, так как используется нечасто. Но это может быть необходимо, так как когда вы перегружаете 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
является полной противоположностью защитного кодирования.
По умолчанию новый оператор размещения не существует для класса, поэтому при вызове new(p) Test(i);
компилятор C++ не может найти определение закомментированного функцию в приведенном выше примере. Если вы раскомментируете оператор размещения, новый для вашего класса, и закомментируете «обычный», тогда будет использоваться «обычный» новый оператор по умолчанию, и ваш код будет скомпилирован.
реализации std::_Construct используют global новое размещение. Так что опасения по поводу совместимости с STL не должны вызывать беспокойства. Но беспокойство по поводу взлома существующего кода, который, возможно, был написан
новой ((void*)p) вещью;
вместо
::new ((void*)p) вещь;
, безусловно, верное замечание.