Стандарты программирования на С++. 101 правило и рекомендация | страница 81
>T::operator new
, что совершенно логично, если выделение памяти прошло успешно, но произошел сбой в конструкторе. "Соответствующая" сигнатура оператора >delete
имеет вид >void operator delete(void*, параметры_оператора_new)
.Теперь перейдем к самому интересному. Стандарт С++ ([C++03] §5.3.4(17)) гласит, что приведенный выше код будет генерироваться тогда и только тогда, когда реально существует соответствующая перегрузка оператора >delete
. В противном случае код вообще не будет вызывать никакого оператора >delete
при сбое в конструкторе. Другими словами, при сбоях в конструкторе мы получим утечку памяти. Из шести проверенных нами распространенных компиляторов только два выводили предупреждение в такой ситуации. Вот почему каждый перегруженный оператор >void* operator new(parms)
должен сопровождаться соответствующей перегрузкой >void operator delete(void*, parms)
.
Размещающий оператор >new
>void* T::operator new(size_t, void* p) { return p; }
не требует наличия соответствующего оператора >delete
, поскольку реального выделения памяти при этом не происходит. Все протестированные нами компиляторы не выдавали никаких предупреждений по поводу отсутствия оператора >void T::operator delete(void*, size_t, void*)
.
[C++03] §5.3.4 • [Stroustrup00] §6.2.6.2, §15.6 • [Sutter00] §36
46. При наличии пользовательского >new
следует предоставлять все стандартные типы этого оператора
Если класс определяет любую перегрузку оператора >new
, он должен перегрузить все три стандартных типа этого оператора — обычный >new
, размещающий и не генерирующий исключений. Если этого не сделать, то эти операторы окажутся скрытыми и недоступными пользователям вашего класса.
Обычно пользовательские операторы >new
и >delete
нужны очень редко, но если они все же оказываются необходимы, то вряд ли вы захотите, чтобы они скрывали встроенные сигнатуры.
В С++, после того как вы определите имя в области видимости (например, в области видимости класса), все такие же имена в охватывающих областях видимости окажутся скрыты (например, в базовых классах или охватывающих пространствах имен), так что перегрузка никогда не работает через границы областей видимости. Когда речь идет об имени оператора >new
, необходимо быть особенно осторожным и внимательным, чтобы не усложнять жизнь себе и пользователям вашего класса.
Пусть вы определили следующий оператор >new
, специфичный для класса: