Intereting Posts
Компилировать 14-код c ++ с g ++ Получить сообщение об ошибке исключения для проверки google В какой момент остановилось переупорядочение кода в оптимизации на C ++? связывание ошибок, в то время как отдельный парсер с использованием повышающего духа x3 Пространство имен Qt Ui Как отсортировать многомерный вектор поплавков? Когда следует использовать make_heap и Priority Queue? сравнение указателей «<» с одним последним элементом элемента массива Преобразование CryptoPP :: Integer в LPCTSTR Проблема, когда файл #import C ++ Header в iPhone / iPad Project Как запустить службу повышения asio resolver для большего количества streamов? Инициализация типов элементов базового classа шаблонов в списках инициализаторов производного classа boost :: chrono nanoseconde windows7 удаление буфера с помощью другого типа указателя? C ++, в частности передавая аргументы конструктора объектам, выделенным с помощью boost :: interprocess :: cached_adaptive_pool

Оператор удаляет неожиданное поведение подписи

В своей книге C ++ Programming Language (4-е изд.), Stroustroup упомянула, что глобальный оператор new & delete может быть перегружен путем написания глобальных функций со следующими сигнатурами:

void* operator new(size_t);               // use for individual object void* operator new[](size_t);             // use for array void operator delete(void*, size_t);      // use for individual object void operator delete[](void*, size_t);    // use for array 

ПРИМЕЧАНИЕ. Параметр size_t передается для удаления, чтобы определить правильный размер объекта, особенно при удалении производного объекта, на который указывает базовый указатель (база требует виртуального dtor, так что правильный размер передается).

Я пытался перегрузить глобальные версии для отдельного объекта. Оператор новый отлично работает. Оператор delete с указанной выше сигнатурой работает нормально, но delete не вызывает вызов. Если я изменю подпись удаления так, что она просто примет пустоту *, она будет вызвана. В чем может быть проблема:

Вот код:

 void * operator new (size_t size) { cout << "My operator new called\n"; auto p = malloc(size); return p; } void operator delete (void * ptr, size_t size) // Removing size_t parameter makes it work { cout << "My operator delete called\n"; free(ptr); } 

Странным является также тот факт, что если я сделаю оператор удаляющим член classа, чтобы его перегружать только для этого classа, как удалять сигнатуры (с size_t и без size_t), похоже, работают!

Передача параметра size_t в delete кажется логичным, как описано в примечании, которое я упомянул. Но что может быть причиной такого поведения? Я использую VS2013 для тестирования примеров.

Из проекта C ++ 1y:

5.3.5 Удалить [expr.delete]

[…]
11 Когда выполняется выражение-удаление, выбранная функция освобождения должна вызываться с адресом блока хранения, подлежащим возврату в качестве его первого аргумента, и (если используется функция двухпараметрического дезадаптации) размер блока как его второй аргумент.83

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

17.6.4.6 Функции [replacement.functions] функции [replacement.functions]

1, пункты 18-30 и Приложение D описывают поведение многочисленных функций, определенных стандартной библиотекой C ++. Однако при некоторых обстоятельствах некоторые из этих описаний функций также применяются к функциям замены, определенным в программе (17.3).
2 Программа на C ++ может предоставить определение для любой из двенадцати динамических функций распределения памяти, объявленных в заголовке (3.7.4, 18.6):

 operator new(std::size_t) operator new(std::size_t, const std::nothrow_t&) operator new[](std::size_t) operator new[](std::size_t, const std::nothrow_t&) perator delete(void*) operator delete(void*, const std::nothrow_t&) operator delete[](void*) operator delete[](void*, const std::nothrow_t&) 

заметьте меня: следующие четыре являются новыми в C ++ 1y

 operator delete(void*, std::size_t) operator delete(void*, std::size_t, const std::nothrow_t&) operator delete[](void*, std::size_t) operator delete[](void*, std::size_t, const std::nothrow_t&) 

3 Определения программы используются вместо стандартных версий, предоставляемых реализацией (18.6). Такая замена происходит до запуска программы (3.2, 3.6). Определения программы не должны указываться как встроенные. Диагностика не требуется.

Также взгляните на предложение, которое вводит размер освобождения в C ++ 1y:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3536.html

В C ++ 11, не-член void operator delete(void*, size_t) является «освобождением места размещения с дополнительными аргументами». Это соответствует распределению размещения с дополнительными аргументами (если вы определили один): void *operator new(size_t, size_t) .

Пояснение этого, в соответствии с 3.7.4.2, T::operator delete(void*, size_t) является обычной функцией освобождения, но N3337 не говорит, что ::operator delete(void *, size_t) является обычной функцией освобождения; на самом деле, что подпись для ::operator delete не появляется нигде в документе. В частности, 17.6.4.6 не перечисляет его среди глобальных версий.

В C ++ 1y, ::operator delete(void*, size_t) – обычная функция освобождения (то есть без размещения). Мне кажется, что это разрывное изменение между C ++ 11 и C ++ 1y.

Согласно N3797, в C ++ 1y, если вы замените operator delete(void *) вы также должны заменить operator delete(void *, size_t) и наоборот. (В противном случае, по-видимому, программа плохо сформирована).

Также согласно N3797, любая из этих двух функций может быть вызвана для освобождения, но я не вижу четкой спецификации того, в каких обстоятельствах эта функция вызывается.

Примечание: перегрузка – неправильный термин; когда вы определяете обычный оператор распределения, он заменяет стандартную версию библиотеки.