内存管理
基本体
分配内存和释放内存
方式
分配 | 释放 | 类别 | 能否重载 |
---|---|---|---|
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++提供一个内存检查函数,让用户提供
-
让更多的内存可用
-
调用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;
}