内存管理
基本体
分配内存和释放内存
方式
分配 | 释放 | 类别 | 能否重载 |
malloc() | free() | c函数 | 不可 |
new | delete | c++表达式 | 不可 |
::operator new() | ::operator delete() | c++函数 | 可 |
allocator::allocate() | allocator::deallocate() | c++标准库 | 可自由设计并且搭配任何容器 |
示例
#include <complex> #include <stdlib.h> using namespace std; int main() { char *p = (char *)malloc(512); p[0] = 'c'; free(p); complex<int> *p2 = new complex<int>; delete p2; void *p3 = ::operator new(512); ::operator delete(p3); #ifdef __GNUC__ void *p5 = allocator<int>().allocate(7); allocator<int>().deallocate((int *)p5,7); #endif return 0; }
new 和 delete
不能直接调用构造函数,但是可以直接调用析构函数
#include <stdlib.h> #include <string> #include <iostream> using namespace std; class MemoryTest { public: MemoryTest() { cout << "MemoryTest"<< endl; } ~MemoryTest() { cout << "~MemoryTest"<< endl; } }; int main() { // MemoryTest *str = new MemoryTest(); // str->MemoryTest(); MemoryTest str2; // str->~MemoryTest(); str2.~MemoryTest(); return 0; }
如果类内有指针则会出现
错误
class MemoryTest { public: MemoryTest() { p = new string("123456"); cout << *p << endl; } ~MemoryTest() { delete p; } private: string *p; }; int main() { // MemoryTest *str = new MemoryTest(); // str->MemoryTest(); MemoryTest str2; // str->~MemoryTest(); str2.~MemoryTest(); return 0; }
正确
#include <complex> #include <stdlib.h> #include <string> #include <iostream> using namespace std; class MemoryTest { public: MemoryTest() { p = new string("123456"); cout << *p << endl; } ~MemoryTest() { if(p) { delete p; p = nullptr; } } private: string *p{nullptr}; }; int main() { // MemoryTest *str = new MemoryTest(); // str->MemoryTest(); MemoryTest str2; // str->~MemoryTest(); str2.~MemoryTest(); return 0; }
深拷贝和浅拷贝
#include <complex> #include <stdlib.h> #include <string> #include <iostream> using namespace std; class A { public: A(int _data) : data(_data){} ~A(){ cout << data << endl; } private: int data; }; int main() { A a(5); A b = a; return 0; }
错误
class A { public: A(int _size) : size(_size) { data = new int[size]; } A(){}; ~A() { delete [] data; } private: int* data; int size; }; int main() { A a(5), b = a; }
正确
class A { public: A(int _size) : size(_size) { data = new int[size]; } A(){}; A(const A& _A) : size(_A.size) data = new int[size]; } ~A() { delete [] data; } private: int* data; int size; }; int main() { A a(5), b = a; }
new[] 和 delete[]
#include <stdlib.h> #include <string> #include <iostream> using namespace std; class MemoryTest { public: MemoryTest():id_(0) { cout << this << "default MemoryTest id =" << id_ << endl; } MemoryTest(int id):id_(id) { cout << this << "default MemoryTest id =" << id_ << endl; } ~MemoryTest() { cout << this << "default ~MemoryTest id =" << id_ << endl; } private: int id_; }; int main() { MemoryTest *str = new MemoryTest[3]; delete[] str; int *p = new int[20]; delete p; // 内置类型析构函数没有意义时候删除不会报错,但是不建议这么使用 return 0; }
调用构造函数修改
#include <stdlib.h> #include <string> #include <iostream> using namespace std; class MemoryTest { public: MemoryTest():id_(0) { cout << this << " default MemoryTest id =" << id_ << endl; } MemoryTest(int id):id_(id) { cout << this << " default MemoryTest id =" << id_ << endl; } ~MemoryTest() { cout << this << " default ~MemoryTest id =" << id_ << endl; } private: int id_; }; int main() { MemoryTest *str = new MemoryTest[3]; MemoryTest *tmp = str; for(int i = 0; i < 3; ++i) new (tmp++) MemoryTest(i); delete[] str; return 0; }
placement new/placement delete
#include <stdlib.h> #include <string> #include <iostream> using namespace std; class MemoryTest { public: MemoryTest():id_(0) { cout << this << " default MemoryTest id =" << id_ << endl; } MemoryTest(int id):id_(id) { cout << this << " default MemoryTest id =" << id_ << endl; } ~MemoryTest() { cout << this << " default ~MemoryTest id =" << id_ << endl; } private: int id_; }; int main() { char *buf = new char[sizeof(MemoryTest)*3]; MemoryTest *test = new (buf)MemoryTest(); delete[] buf; return 0; }
重载 ::operator new / ::operator delete
#include <stdlib.h> #include <string> #include <iostream> using namespace std; void* myAlloc(size_t size) { return malloc(size); } void myFree(void *pt) { return free(pt); } class A { public: inline void * operator new (size_t size) { cout << "global new " << std::endl; return myAlloc(size); } inline void * operator new[] (size_t size) { cout << "global new[] " << std::endl; return myAlloc(size); } inline void operator delete (void *pt) { cout << "global delete " << std::endl; myFree(pt); } inline void operator delete[] (void *pt) { cout << "global delete[] " << std::endl; myFree(pt); } }; int main() { A *c = new A; delete c; A *c2 = new A[10]; delete[] c2; return 0; }
重载 new() / delete()
#include <stdlib.h> #include <string> #include <iostream> using namespace std; void* myAlloc(size_t size) { return malloc(size); } void myFree(void *pt) { return free(pt); } class Bad : public exception { }; class A { public: A() { cout << "A" << std::endl; } A(int i) : id_(i) { cout << "A(int i)" << std::endl; // 本来抛出异常应该调用析构函数,但是我这里程序会进行不下去,应该是编译器做了优化,暂时未查询原因 // throw Bad{}; } inline void * operator new (size_t size) { cout << "operator new (size_t size)" << std::endl; return myAlloc(size); } inline void * operator new (size_t size, void *start) { cout << "operator new (size_t size, void *start) " << std::endl; return myAlloc(size); } inline void * operator new (size_t size, long extra) { cout << "operator new (size_t size, long extra)" << std::endl; return myAlloc(size+extra); } inline void * operator new (size_t size, long extra, char init) { cout << "operator new (size_t size, long extra, char init) " << std::endl; return myAlloc(size+extra); } inline void operator delete (void *, size_t t) { cout << "operator delete (void *, size_t t) " << std::endl; } inline void operator delete (void *, void *) { cout << "operator delete (void *, void *) " << std::endl; } inline void operator delete (void *, long) { cout << "operator delete (void *, long) " << std::endl; } inline void operator delete (void *, long, char) { cout << "operator delete (void *, long, char) " << std::endl; } void myPrint() { std::cout << "test" << std::endl; } private: int id_; }; int main() { string s = "ccc"; A *a = new A; A *a1 = new (a)A; A *a2 = new (100)A; A *a3 = new (100,'a')A; A *a4 = new (100)A(1); A *a5 = new (100,'a')A(1); A *a6 = new (a)A(1); A *a7 = new A(1); return 0; }
空间划分
#include <stdlib.h> #include <string> #include <iostream> #include <valarray> using namespace std; class Screen { public: Screen(int x):i(x) { } int get(){return i;}; void * operator new (size_t size) { Screen *p; if(!freeStore) { size_t chunk = screenChunk * size; freeStore = p = reinterpret_cast<Screen * >(new char[chunk]); for(;p != &freeStore[screenChunk-1];++p) { p->next = p+1; } p->next = 0; } p = freeStore; freeStore = freeStore->next; return p; } void operator delete (void *p,size_t size) { static_cast<Screen *>(p)->next = freeStore; freeStore = static_cast<Screen *>(p); } private: Screen *next; static Screen *freeStore; static const int screenChunk; int i; }; Screen *Screen::freeStore = 0; const int Screen::screenChunk = 24; int main() { size_t const N = 100; Screen *p[N]; for(int i = 0; i < N; ++i) { p[i] = new Screen(i); } for(int i = 0; i < 10; ++i) { cout << p[i] << endl; } for(int i = 0; i < N; ++i) { delete p[i]; } return 0; }
改造
#include <stdlib.h> #include <string> #include <iostream> #include <valarray> using namespace std; class Airplane { private: struct AirplaneRep { unsigned long miles; char type; }; union { AirplaneRep rep; Airplane *next; }; static const int BLOCK_SIZE; static Airplane *headOfFreeList; public: unsigned long getMiles(){return rep.miles;} char getType(){return rep.type;} void set(unsigned long m ,char t) { rep.miles = m; rep.type = t; } public: void * operator new(size_t size) { // 为了防止继承造成的空间大小不一致问题 if(size != sizeof(Airplane)) return ::operator new(size); Airplane *p = headOfFreeList; if(p) headOfFreeList = p->next; else { Airplane *newBlock = static_cast<Airplane *>(::operator new (BLOCK_SIZE * sizeof(Airplane))); for(int i = 1; i < BLOCK_SIZE -1; ++i) { newBlock[i].next = &newBlock[i+1]; } newBlock[BLOCK_SIZE -1].next = 0; p = newBlock; headOfFreeList = &newBlock[1]; } return p; } void operator delete (void *dataObj,size_t size) { if(dataObj == 0) return; if(size != sizeof(Airplane)) { ::operator delete(dataObj); return; } Airplane *carcass = static_cast<Airplane *>(dataObj); carcass->next = headOfFreeList; headOfFreeList = carcass; } }; const int Airplane:: BLOCK_SIZE = 512; Airplane *Airplane::headOfFreeList; int main() { cout << sizeof(Airplane) << endl; size_t const N = 100; Airplane *p[N]; for(int i = 0; i < N; ++i) { p[i] = new Airplane; } p[1]->set(1000,'A'); p[2]->set(1000,'B'); p[3]->set(1000,'C'); p[4]->set(1000,'D'); p[5]->set(1000,'E'); p[6]->set(1000,'F'); p[7]->set(1000,'G'); p[8]->set(1000,'H'); p[9]->set(1000,'I'); for(int i = 0; i < 10; ++i) { cout << p[i] << endl; } for(int i = 0; i < N; ++i) { delete p[i];c } return 0; }
分配器
#include <stdlib.h> #include <string> #include <iostream> #include <valarray> using namespace std; class Allocator { public: void *allocate(size_t size) { obj *p; if(!freeStore) { size_t chunk = CHUNK * size; freeStore = p = (obj*) malloc(chunk); for(int i = 0; i < CHUNK -1; ++i) { p->next = (obj*)((char *)p +size); p = p->next; } p->next = nullptr; } p =freeStore; freeStore = freeStore->next; return p; } void deallocate(void *p,size_t size) { ((obj*)p)->next = freeStore; freeStore = (obj*)p; } private: struct obj { struct obj *next; }; obj *freeStore = nullptr; const int CHUNK = 5; }; class Foo { public: long L; string str; static Allocator myAlloc; public: Foo(long l):L(l){} void * operator new(size_t size) { return myAlloc.allocate(size); } void operator delete (void * p, size_t size) { return myAlloc.deallocate(p,size); } }; Allocator Foo::myAlloc; int main() { Foo *p[100]; cout << sizeof(Foo) <<endl; for(int i =0; i< 19; i++) { p[i] = new Foo(i); cout << p[i] << " " << p[i]->L << endl; } cout << 0x633b40-0x633ae0 << " " << 0x633b68-0x633b40 << endl; for(int i =0; i< 19; i++) { delete p[i]; } return 0; }
使用宏替换
#include <stdlib.h> #include <string> #include <iostream> #include <valarray> using namespace std; class Allocator { public: void *allocate(size_t size) { obj *p; if(!freeStore) { size_t chunk = CHUNK * size; freeStore = p = (obj*) malloc(chunk); for(int i = 0; i < CHUNK -1; ++i) { p->next = (obj*)((char *)p +size); p = p->next; } p->next = nullptr; } p =freeStore; freeStore = freeStore->next; return p; } void deallocate(void *p,size_t size) { ((obj*)p)->next = freeStore; freeStore = (obj*)p; } private: struct obj { struct obj *next; }; obj *freeStore = nullptr; const int CHUNK = 5; }; #define DECLARE_POOL_ALLOC_1() \ public: \ void * operator new(size_t size){ return myAlloc.allocate(size); } \ void operator delete (void * p, size_t size){ return myAlloc.deallocate(p,size); } \ protected: \ static Allocator myAlloc; #define IMPLEMENT_POOL_ALLOC_1(ClassName) \ Allocator ClassName::myAlloc; class Foo { DECLARE_POOL_ALLOC_1(); public: long L; string str; public: Foo(long l):L(l){} }; IMPLEMENT_POOL_ALLOC_1(Foo); int main() { Foo *p[100]; cout << sizeof(Foo) <<endl; for(int i =0; i< 19; i++) { p[i] = new Foo(i); cout << p[i] << " " << p[i]->L << endl; } cout << 0x633b40-0x633ae0 << " " << 0x633b68-0x633b40 << endl; for(int i =0; i< 19; i++) { delete p[i]; } return 0; }
new_handler
new (nothrow)Foo; 检查是否成功
typedef void (*new_handler)();
new_handler set_new_handler(new_handler p) throw();
当内存溢出的时候,C++提供一个内存检查函数,让用户提供
1.让更多的内存可用
2.调用abort()和exit();
#include <stdlib.h> #include <iostream> #include <valarray> #include <new> #include <cassert> using namespace std; void noMoreMemory() { cerr << "out of memory" << endl; abort(); // 不abort 的话会不断打印这个err } int main() { set_new_handler(noMoreMemory); int *p = new int[10000000000000]; assert(p); return 0; }
default delete
#include <stdlib.h> #include <iostream> #include <valarray> #include <new> #include <cassert> using namespace std; class Foo { public: // static void *operator new(size_t size) = default; // static void *operator delete(void *,size_t size) = default; static void *operator new[](size_t size) = delete; static void operator delete [](void *,size_t size) = delete; }; int main() { Foo *foo = new Foo; delete foo; // Foo *foo2 = new Foo[100]; // delete foo[]; return 0; }