Last active
August 29, 2015 14:19
-
-
Save santa4nt/945854f2d261193735b0 to your computer and use it in GitHub Desktop.
Sample code for overriding operator new/delete in C++.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <new> | |
#include <iostream> | |
#include <iomanip> | |
#include <exception> | |
#include <cstdlib> | |
// global overrides of new and delete | |
void* _new(std::size_t); | |
void* operator new (std::size_t sz) | |
{ | |
void *mem = _new(sz); | |
std::cout << std::hex << "::new(0x" << sz << ") => 0x" << mem << std::endl; | |
return mem; | |
} | |
void* operator new (std::size_t sz, unsigned int arg) | |
{ | |
void *mem = _new(sz); | |
std::cout << std::hex << "::new(0x" << sz << ") => 0x" << mem; | |
// showcasing overloading `operator new` with additional parameters | |
std::cout << "; arg: 0x" << arg << std::endl; | |
return mem; | |
} | |
void* operator new[] (std::size_t sz) | |
{ | |
void *mem = _new(sz); | |
std::cout << std::hex << "::new[](0x" << sz << ") => 0x" << mem << std::endl; | |
return mem; | |
} | |
void* _new(std::size_t sz) | |
{ | |
void *mem = malloc(sz); // returns NULL on failures | |
if (mem == NULL) | |
{ | |
throw std::bad_alloc(); // simulate standard C++ new behavior | |
} | |
return mem; | |
} | |
void operator delete (void *ptr) | |
{ | |
std::cout << "::delete(0x" << std::hex << ptr << ")" << std::endl; | |
free(ptr); // nullptr-safe | |
} | |
void operator delete (void *ptr, unsigned int arg) | |
{ | |
std::cout << "::delete(0x" << std::hex << ptr; | |
// showcasing overloading `operator delete` with additional parameters | |
std::cout << "; arg: 0x" << arg << ")" << std::endl; | |
free(ptr); // nullptr-safe | |
} | |
void operator delete[] (void *ptr) | |
{ | |
std::cout << "::delete[](0x" << std::hex << ptr << ")" << std::endl; | |
free(ptr); // nullptr-safe | |
} | |
// class-specific overrides of new and delete | |
class BaseObj | |
{ | |
public: | |
// static is always implicit with operator new(); explicitly stated here for clarity | |
static void* operator new (std::size_t sz) | |
{ | |
void *mem = ::operator new (sz); // might throw std::bad_alloc | |
std::cout << std::hex << "BaseObj::new(0x" << sz << ") => 0x" << mem << std::endl; | |
return mem; | |
} | |
static void* operator new[] (std::size_t sz) | |
{ | |
void *mem = ::operator new[] (sz); | |
std::cout << std::hex << "BaseObj::new[](0x" << sz << ") => 0x" << mem << std::endl; | |
return mem; | |
} | |
static void operator delete (void *ptr) noexcept | |
{ | |
std::cout << "BaseObj::delete(0x" << std::hex << ptr << ")" << std::endl; | |
::operator delete (ptr); | |
} | |
static void operator delete[] (void *ptr) noexcept | |
{ | |
std::cout << "BaseObj::delete[](0x" << std::hex << ptr << ")" << std::endl; | |
::operator delete[] (ptr); | |
} | |
}; | |
// `new Derived;` will call `BaseObj::operator new` | |
class Derived : public BaseObj | |
{ | |
}; | |
// `new C;` will call the global `::operator new` | |
class C { | |
private: | |
char _carr[20]; | |
}; | |
class CExc : public C { | |
public: | |
CExc() | |
{ | |
throw std::exception(); | |
} | |
}; | |
int main() | |
{ | |
std::cout << "BaseObj *obj = new Derived;" << std::endl; | |
BaseObj *obj = new Derived; | |
std::cout << std::endl; | |
std::cout << "Derived *objArr = new Derived[10];" << std::endl; | |
Derived *objArr = new Derived[10]; | |
std::cout << std::endl; | |
std::cout << "C *obc = new C; // private: char _carr[20];" << std::endl; | |
C *obc = new C; | |
std::cout << std::endl; | |
std:: cout << "C *obc2 = new (0xbeefcafe) C;" << std::endl; | |
C *obc2 = new (0xbeefcafe) C; | |
std::cout << std::endl; | |
std:: cout << "delete obj;" << std::endl; | |
delete obj; | |
std::cout << std::endl; | |
std:: cout << "delete[] objArr;" << std::endl; | |
delete[] objArr; | |
std::cout << std::endl; | |
std:: cout << "delete obc;" << std::endl; | |
delete obc; | |
std::cout << std::endl; | |
// there is no "placement delete" expression; must call explicitly | |
std:: cout << "::operator delete (obc2, 0xbeefcafe);" << std::endl; | |
::operator delete (obc2, 0xbeefcafe); | |
std::cout << std::endl; | |
try | |
{ | |
std:: cout << "CExc *ocexc = new (0xdeadbeef) CExc;" << std::endl; | |
CExc *ocexc = new (0xdeadbeef) CExc; | |
} | |
catch (const std::exception&) | |
{ | |
// placement `operator delete (void*,unsigned int)` should be called here | |
std::cout << "Caught exception!" << std::endl; | |
} | |
return 0; | |
} | |
/** | |
* Sample output: | |
* | |
* $ g++ -std=c++11 -o onew onew.cc && ./onew | |
* ----------------------------------------------------------------------------- | |
* BaseObj *obj = new Derived; | |
* ::new(0x1) => 0x0x5a1c040 | |
* BaseObj::new(0x1) => 0x0x5a1c040 | |
* | |
* Derived *objArr = new Derived[10]; | |
* ::new[](0xa) => 0x0x5a1c090 | |
* BaseObj::new[](0xa) => 0x0x5a1c090 | |
* | |
* C *obc = new C; // private: char _carr[20]; | |
* ::new(0x14) => 0x0x5a1c0e0 | |
* | |
* C *obc2 = new (0xbeefcafe) C; | |
* ::new(0x14) => 0x0x5a1c140; arg: 0xbeefcafe | |
* | |
* delete obj; | |
* BaseObj::delete(0x0x5a1c040) | |
* ::delete(0x0x5a1c040) | |
* | |
* delete[] objArr; | |
* BaseObj::delete[](0x0x5a1c090) | |
* ::delete[](0x0x5a1c090) | |
* | |
* delete obc; | |
* ::delete(0x0x5a1c0e0) | |
* | |
* ::operator delete (obc2, 0xbeefcafe); | |
* ::delete(0x0x5a1c140; arg: 0xbeefcafe) | |
* | |
* CExc *ocexc = new (0xdeadbeef) CExc; | |
* ::new(0x14) => 0x0x5a1c1a0; arg: 0xdeadbeef | |
* ::delete(0x0x5a1c1a0; arg: 0xdeadbeef) | |
* Caught exception! | |
* ----------------------------------------------------------------------------- | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment