§3.7.4.2/2 содержит следующие предложения:
Глобальная
operator delete
ровно с двумя параметрами, второй из которых имеет типstd::size_t
, является обычной функцией освобождения памяти. Точно так же глобальнаяoperator delete[]
с ровно одним параметром является обычной функцией освобождения памяти. Глобальный операторdelete[]
ровно с двумя параметрами, второй из которых имеет типstd::size_t
, является обычной функцией освобождения памяти.37
37) Эта функция освобождения исключает использование функции распределения void operator new(std::size_t, std::size_t)
в качестве функции распределения размещения.
Я не только не понял причины этой сноски, но также заметил, что этой формы размещения, упомянутой в сноске, не существует в §18.6.1.3 Формы размещения [new.delete.placement].
Изменить, чтобы проверить, что говорит @Sander De Dicker в своем ответе. , я протестировал следующий фрагмент:
#include <iostream>
void* operator new (std::size_t count, int i1, int i2, int i3){
void *p = malloc(count);
if (!p) throw std::bad_alloc{};
std::cout << "operator new" << '\n';
return p;
}
void operator delete (void* p, int j1, int j2, int j3)
{
free(p);
std::cout << "operator delete" << '\n';
}
class A {
public:
A() { std::cout << "A()" << '\n'; };
~A() { std::cout << "~A()" << '\n'; }
};
int main()
{
try
{
A *p = new(0, 0, 0) A;
delete p;
}
catch (std::bad_alloc&) { exit(1); }
}
Во всех трех доступных мне компиляторах (VS2015, clang и g++) код вызывал размещение operator new(size_t, int, int, int)
, но не вызывал размещение operator delete(void*, int, int, int)
, а operator delete(void*)
. Теперь я еще больше смущен, чем когда задавал вопрос.
operator new(size_t, size_t)
, потому что для этого требуется соответствующийoperator delete(size_t, size_t)
для удалений, которые происходят из-за исключений, возникающих во время построения в распределении с помощью этой новой функции размещения. - person dyp   schedule 30.11.2015operator new
. - person Belloc   schedule 30.11.2015A()
. В этом случае вызываетсяoperator delete(void*, int, int, int)
. Но согласно §5.3.4/22 его также следует вызывать в приведенном выше примере. Почему это не так? - person Belloc   schedule 30.11.2015delete x;
указывается отдельно (в 5.3.5 [expr.delete]) и использует только обычные функции освобождения. Практическая причина: компилятор знает только, какие аргументы передать размещению удаления, когда вы находитесь в размещении new. - person T.C.   schedule 30.11.2015Practical reason: the compiler only knows what arguments to pass to the placement delete while you are in the placement new.
Великолепно. - person Belloc   schedule 30.11.2015A()
бросает, но исключение не перехватывается вmain()
, ни~A()
, ниoperator delete(void*, int, int, int)
не вызываются. Я пытался найти объяснение, но безрезультатно. - person Belloc   schedule 01.12.2015~A()
никогда не будет вызываться, так какA
никогда не создается успешно. Освобождение является частью раскручивания стека, и когда соответствующий обработчик не найден, от реализации зависит, раскручивается ли стек. - person T.C.   schedule 01.12.2015~A()
. Это было просто моим отвлечением. Но для того, чтобыoperator delete(void*, int, int, int)
был вызван, исключение, генерируемоеA()
, должно быть перехвачено блоком try, окружающим вызов конструктора. Разве это не приведет к раскручиванию стека? - person Belloc   schedule 01.12.2015new
. Мне нужно проверить, как это указано в стандарте, но реализации по существу рассматривают освобождение при броске как еще один деструктор, который запускается, когда происходит раскручивание стека. То есть это точно так же, как если бы вы вызывалиoperator new
, скрывали результат в охраннике области, который вызывает функцию освобождения при уничтожении, вызываете конструктор, а затем отклоняете охрану области. Я могу написать это вручную и заставить clang/gcc создать идентичную сборку. - person T.C.   schedule 01.12.2015