Самой яркой особенностью языка программирования C++ перед привычной мне Java является необходимость обеспечивать ручное управление памятью и на этом пути разработчика поджидает множество интересных особенностей. Например, если мы переопределяем оператор new, снабдив его нужными исключительно нам аргументами (так называемая class-specific placement allocation functions), то необходимо подобным же образом переопределить и оператор delete (имеется ввиду, что нужно определить оператор delete, имеющий сигнатуру void operator delete(void *ptr, user-defined-args...), иначе при возникновении исключительной ситуации в конструкторе класса будет не понятно какой оператор delete следует вызывать, чтобы освободить уже выделенную для создаваемого объекта данного класса память. Произойдет утечка памяти.
К счастью компилятор MSVC информирует разработчика об опасности, выбрасывая исключение C4291 no matching operator delete found; memory will not be freed if initialization throws an exception (код должен компилироваться с флагами компиляции /EHsc /W1). Например:
[1/2] Building CXX object src\memory\CMakeFiles\placement-new-delete.dir\PlacementNewDelete.cpp.obj
..\src\memory\PlacementNewDelete.cpp(67): warning C4291: 'void *MyClassA::operator new(size_t,MyAllocator &)': no matching operator delete found; memory will not be freed if initialization throws an exception
..\src\memory\PlacementNewDelete.cpp(32): note: see declaration of 'MyClassA::operator new'
[2/2] Linking CXX executable src\memory\placement-new-delete.exe
Подробно предупреждение компилятора C4291 описано в одноименной статье на MSDN.
Проблема заключается в том, что реализовать соответствующий оператор delete может быть не так то и просто. Как нетрудно заметить, оператор new в любом случае принимает аргумент size - размер требуемой памяти в байтах, оператор же delete такого параметра не принимает, а он может использоваться при выделении памяти и быть необходим, чтобы вернуть ее операционной системе.
Рассмотрим такой паттерн: использование для выделения памяти стороннего аллокатора, реализующего два метода: allocate и deallocate, каждый из которых принимает на вход параметр size_t size. Такой код довольно часто встречается в реализации JIT-компилятора в наборе компонентов для построения виртуальных машин Eclipse OMR, из чего я сделал вывод, что паттерн довольно распространен.
Предупреждение компилятора C4291
К счастью компилятор MSVC информирует разработчика об опасности, выбрасывая исключение C4291 no matching operator delete found; memory will not be freed if initialization throws an exception (код должен компилироваться с флагами компиляции /EHsc /W1). Например:
[1/2] Building CXX object src\memory\CMakeFiles\placement-new-delete.dir\PlacementNewDelete.cpp.obj
..\src\memory\PlacementNewDelete.cpp(67): warning C4291: 'void *MyClassA::operator new(size_t,MyAllocator &)': no matching operator delete found; memory will not be freed if initialization throws an exception
..\src\memory\PlacementNewDelete.cpp(32): note: see declaration of 'MyClassA::operator new'
[2/2] Linking CXX executable src\memory\placement-new-delete.exe
Подробно предупреждение компилятора C4291 описано в одноименной статье на MSDN.
Проблема заключается в том, что реализовать соответствующий оператор delete может быть не так то и просто. Как нетрудно заметить, оператор new в любом случае принимает аргумент size - размер требуемой памяти в байтах, оператор же delete такого параметра не принимает, а он может использоваться при выделении памяти и быть необходим, чтобы вернуть ее операционной системе.
Использование аллокатора для размещения объектов в памяти
Рассмотрим такой паттерн: использование для выделения памяти стороннего аллокатора, реализующего два метода: allocate и deallocate, каждый из которых принимает на вход параметр size_t size. Такой код довольно часто встречается в реализации JIT-компилятора в наборе компонентов для построения виртуальных машин Eclipse OMR, из чего я сделал вывод, что паттерн довольно распространен.