Мы знаем из стандарта c ++ 11 (также верно в стандарте c ++ 98/03) (см. Ниже), мы не можем попытаться заменить оператор новой функцией — помещением формы в глобальное пространство, как это уже было определено.
18.6.1.3 Формы размещения [new.delete.placement]
Эти функции зарезервированы, программа на C ++ может не определять функции, которые смещают
версии в стандартной библиотеке C ++ (17.6.4). Положения
(3.7.4) не применяются к этим зарезервированным формам размещения оператора новых
и оператор удаления.
Это было доказано пунктом 2> во фрагменте ниже, ошибка компиляции, как и ожидалось.
Но я все еще могу переопределить новое место размещения на уровне класса, которое отлично работает, см. Пункт (2) во фрагменте ниже. Это почему? Не следует ли компилировать, следует пытаться предотвратить (2), а также в соответствии со стандартом ???
Смотрите мой фрагмент ниже:
class Test
{
public:
Test(int i):m_i(i) { cout << "Test::Test()" << endl; }
~Test() { cout << "Test::~Test()" << endl; }
//(1)class level override placement new
void* operator new (std::size_t size) throw (std::bad_alloc) {
cout << "My class level new" << endl;
return malloc(size);
}
//(2)class level override placement new
void* operator new (std::size_t size, void* ptr) throw() {
cout << "My class level non-throwing placement new" << endl;
return ptr;
}
private:
int m_i;
};
//<1>global replacement for operator new - single object form
void* operator new (std::size_t size) throw (std::bad_alloc) {
cout << "My global new" << endl;
return malloc(size);
}//<2>global replacement for operator new - replcement form
//NB. This is a attempt that definitely fails according to c++ stadnard:
//does get compile error: error: redefinition of 'void* operator new(std::size_t, void*)'
/*
void* operator new (std::size_t size, void* ptr) throw() {
cout << "My global non-throwing placement new" << endl;
return ptr;
}
*/
int main() {
Test* p = new Test(1);
delete p;
cout << "" << endl;
void* mem = operator new(sizeof(Test));
Test* p2 = new(mem) Test(1);
p2->~Test();
operator delete (mem);
return 0;
}
Ниже выводится, как и ожидалось:
My class level new
My global new
Test::Test()
Test::~Test()
My global new
My class level non-throwing placement new
Test::Test()
Test::~Test()
================================================== ================================
Дальнейшее уточнение моего вопроса:
18.6.1.3 Формы размещения Эти функции зарезервированы, программа на C ++ может не определять функции, которые заменяют версии в
стандарт Библиотека C ++ (17.6.4). Положения (3.7.4) не применяются к этим зарезервированным формам размещенияоператора new и оператора delete.
Это объясняет ожидаемую ошибку компиляции в точке <2> в моем фрагменте, так что это нормально.
Но почему я могу сместить формы размещения на уровне класса в точке (2) внутри пояснения класса?
§ 18.6.1.3 перечисляет следующие формы:
void* operator new(std::size_t size, void* ptr) noexcept;
void* operator new[](std::size_t size, void* ptr) noexcept;
void operator delete(void* ptr, void*) noexcept;
void operator delete[](void* ptr, void*) noexcept;
Правило, согласно которому «программа на C ++ не может определять функции, которые заменяют версии в стандартной библиотеке C ++», применяется только к этим четырем объявлениям функций, которые не находятся ни в одном пространстве имен. Если вы делаете свою собственную версию в классе или пространстве имен, это нормально.
На самом деле, иногда ты иметь обеспечить собственное размещение новых. Если вы объявите нормальный operator new
в вашем классе он будет скрывать новое место размещения, предоставляемое стандартной библиотекой, и вам нужно будет добавить свое новое место размещения в классе, если вы когда-либо захотите использовать new (ptr) T(...)
синтаксис.
Это просто гарантирует, что звонок ::new (ptr) T(...)
является гарантированный вести себя как стандартное размещение нового. (Обратите внимание ::
префикс.)
Других решений пока нет …