类内重载 operator new/operator delete 示例
#include <iostream>#include <string>using namespace std;class Foo {public: int _id; int _data; int _num;public: // 如果没有重载的成员函数则调用全局版本 static void *operator new(size_t size); static void operator delete(void *pdead, size_t size); static void *operator new[](size_t size); static void operator delete[](void *pdead, size_t size); Foo() : _id(0) { cout << "default ctor.this=" << this << " id=" << _id << endl; } Foo(int i) : _id(i) { cout << "ctor. this=" << this << " id=" << _id << endl; } // virtual ~Foo() { cout << "dtor. this=" << this << " id=" << _id << endl; }};void *Foo::operator new(size_t size){ Foo *p = (Foo*)malloc(size); cout << "Foo::operator new(), size=" << size << "\t return: " << p << endl; return p;}void Foo::operator delete(void *pdead, size_t size){ cout << "Foo::operator delete(), pdead= " << pdead << " size= " << size << endl; free(pdead);}void *Foo::operator new[](size_t size){ Foo *p = (Foo*)malloc(size); cout << "Foo::operator new[](), size=" << size << "\t return: " << p << endl; return p;}void Foo::operator delete[](void *pdead, size_t size){ cout << "Foo::operator delete[](), pdead= " << pdead << " size= " << size << endl; free(pdead);}int main(){ cout << "sizeof(Foo)=" << sizeof(Foo) << endl; cout << "============" << endl; Foo *p = new Foo(7); delete p; cout << "============" << endl; Foo* pArray = new Foo[5]; delete [] pArray; return 0;}
当 Foo 无虚析构函数时,输入:
sizeof(Foo)=12 // 留神这里 !!============Foo::operator new(), size=12 return: 0x7617b0ctor. this=0x7617b0 id=7dtor. this=0x7617b0 id=7Foo::operator delete(), pdead= 0x7617b0 size= 12============Foo::operator new[](), size=68 return: 0x7617b0default ctor.this=0x7617b8 id=0default ctor.this=0x7617c4 id=0default ctor.this=0x7617d0 id=0default ctor.this=0x7617dc id=0default ctor.this=0x7617e8 id=0dtor. this=0x7617e8 id=0dtor. this=0x7617dc id=0dtor. this=0x7617d0 id=0dtor. this=0x7617c4 id=0dtor. this=0x7617b8 id=0Foo::operator delete[](), pdead= 0x7617b0 size= 68
当 Foo 有虚析构函数时,输入:
sizeof(Foo)=16 // 留神这里 !!============Foo::operator new(), size=16 return: 0xfb8088ctor. this=0xfb8088 id=7dtor. this=0xfb8088 id=7Foo::operator delete(), pdead= 0xfb8088 size= 16============Foo::operator new[](), size=84 return: 0xfb8088default ctor.this=0xfb808c id=0default ctor.this=0xfb809c id=0default ctor.this=0xfb80ac id=0default ctor.this=0xfb80bc id=0default ctor.this=0xfb80cc id=0dtor. this=0xfb80cc id=0dtor. this=0xfb80bc id=0dtor. this=0xfb80ac id=0dtor. this=0xfb809c id=0dtor. this=0xfb808c id=0Foo::operator delete[](), pdead= 0xfb8088 size= 84
- 当类中带有虚函数时,会多占用 4 字节内存空间。(为虚函数表指针,以实现多态)
int main(){ cout << "sizeof(Foo)=" << sizeof(Foo) << endl; cout << "============" << endl; Foo *p = ::new Foo(7); // 留神这里 !! ::delete p; cout << "============" << endl; Foo* pArray = ::new Foo[5]; // 留神这里 !! ::delete[] pArray; return 0;}
当 Foo 无虚析构函数时,输入[类中重载版本 new / delete 未被调用]:
sizeof(Foo)=12============ctor. this=0x7617b0 id=7dtor. this=0x7617b0 id=7============default ctor.this=0x7617b8 id=0default ctor.this=0x7617c4 id=0default ctor.this=0x7617d0 id=0default ctor.this=0x7617dc id=0default ctor.this=0x7617e8 id=0dtor. this=0x7617e8 id=0dtor. this=0x7617dc id=0dtor. this=0x7617d0 id=0dtor. this=0x7617c4 id=0dtor. this=0x7617b8 id=0
当 Foo 有虚析构函数时,输入[类中重载版本 new / delete 未被调用]:
sizeof(Foo)=16============ctor. this=0xfb8088 id=7dtor. this=0xfb8088 id=7============default ctor.this=0xfb808c id=0default ctor.this=0xfb809c id=0default ctor.this=0xfb80ac id=0default ctor.this=0xfb80bc id=0default ctor.this=0xfb80cc id=0dtor. this=0xfb80cc id=0dtor. this=0xfb80bc id=0dtor. this=0xfb80ac id=0dtor. this=0xfb809c id=0dtor. this=0xfb808c id=0
- 如上调用(也就是写上 global scope operator ::), 会绕过前述所有 overloaded functions, 强制应用 global version
重载 new() / delete()
咱们能够重载 class member operator new(), 写出多个版本,前提是每一个版本的申明都必须具备独特的参数列表,其中第一个参数必须是 size_t, 其余参数以 new 所指定的 placement arguments 为初值。 呈现于 new(...) 小括号内的便是所谓的 placement argument。
Foo *pf = new (300, 'c')Foo;
咱们也能够重载 class member operator delete(), 写出多个版本。但它们绝不会被 delete 调用【void operator delete(void*, size_t)
版本被调用】。只有当 new 所调用的构造函数抛出异样,才会调用这些重载版本对应的 operator delete()。它只可能这样被调用,次要用来偿还未能齐全创立胜利的对象所占用的内存空间。
#include <iostream>using namespace std;class Bad {};class Foo {public: Foo() { cout << "Foo::Foo()" << endl; } Foo(int) { cout << "Foo::Foo(int)" << endl; throw Bad(); // 成心在这里抛出异样,测试 placement operator delete } // (1) 个别的 operator new() 重载函数 void *operator new(size_t size) { cout << "operator new(size_t size), size= " << size << endl; return malloc(size); } // (2) 规范库曾经提供的 placement new() 的重载模式 // (这里模仿 standard placement new 的动作, just return ptr) void *operator new(size_t size, void *start) { cout << "operator new(size_t size, void *start), size= " << size << endl; return start; } // (3) 一个簇新的 placement new void *operator new(size_t size, long extra) { cout << "operator new(size_t size, long extra), size= " << size << ' ' << extra << endl; return malloc(size + extra); } // (4) 又一个 placement new void *operator new(size_t size, long extra, char init) { cout << "operator new(size_t size, long extra, char init), size= " << size << ' ' << extra << ' ' << init << endl; return malloc(size + extra); } // (5) 这又是一个 placement new, 但成心写错第一参数 type (它必须是 size_t 以满足失常的 operator new)//! void *operator new(long extra, char init) { // error: 'operator new' takes type size_t ('unsigned int') as first parameter//! cout << "op-new(long, char)" << endl;//! return malloc(extra);//! } // 以下是搭配上述 placement new 的各个 called placement delete. // 当构造函数抛出异样,这里对应的 operator (placement) delete 就会调用. // 应该是要负责开释其搭档兄弟 (placement new) 调配所得的内存. // (1) 这个就是个别的 operator delete() 的重载 void operator delete(void* ptr, size_t) { cout << "operator delete(void*, size_t)" << endl; free(ptr); } // (2) 这个是对应上述的 (2) void operator delete(void *ptr, void*) { cout << "operator delete(void *ptr, void*)" << endl; free(ptr); } // (3) 这个是对应上述的 (3) void operator delete(void *ptr, long) { cout << "operator delete(void *ptr, long)" << endl; free(ptr); } // (4) 这个是对应上述的 (4) void operator delete(void *ptr, long, char) { cout << "operator delete(void *ptr, long, char)" << endl; free(ptr); }private: int m_i;};int main(){ Foo start; Foo *p1 = new Foo; // op-new(size_t) Foo *p2 = new (&start)Foo; // op-new(size_t, void*) Foo *p3 = new (100)Foo; // op-new(size_t, long) Foo *p4 = new (100, 'a')Foo; // op-new(size_t, long, char) delete p1; // 留神这里!! delete p2; // 留神这里!! delete p3; // 留神这里!! delete p4; // 留神这里!! return 0;}
输入:
Foo::Foo()operator new(size_t size), size= 4Foo::Foo()operator new(size_t size, void *start), size= 4Foo::Foo()operator new(size_t size, long extra), size= 4 100Foo::Foo()operator new(size_t size, long extra, char init), size= 4 100 aFoo::Foo()operator delete(void*, size_t)operator delete(void*, size_t)operator delete(void*, size_t)operator delete(void*, size_t)
int main(){ Foo start; Foo *p5 = new (100)Foo(1); // op-new(size_t, long) op-del(void*, long) Foo *p6 = new (100, 'a')Foo(1); // Foo *p7 = new (&start)Foo(1); // Foo *p8 = new Foo(1); // return 0;}
输入:
Foo::Foo()operator new(size_t size, long extra), size= 4 100Foo::Foo(int)terminate called after throwing an instance of 'Bad' // 构造函数抛出异样
阐明
以上应用 mingw81 测试,operator delete(void *, long) 并未被调用;但G2.9的确有调用。
basic_string 应用 new (extra) 裁减申请量
- extra 的作用: 辅助实现援用计数(浅拷贝)