C++ 编译的程序占用内存:
使用 new / delete 直接管理内存:
new : 为对象分配空间并返回一个指向该对象的指针
delete:接受一个动态对象的指针,销毁该对象,并释放与之关联的内存
注意事项:
1、new / delete 需要搭配使用,用 new 申请了一块内存,就必须用 delete 释放该内存。否则会产生内存泄漏。
int main()
int* pi = new int(5); // 用 new 申请内存
delete pi; // delete 释放该内存
return 0;
2、尽量使用 “值初始化” : 用 () 来初始化
int main()
int* pi = new int; // 返回一个 int型随机值
int* pi2 = new int(); // pi2 的值初始化为 0
int* pi3 = new int(10); // pi3 的值初始化为 10
return 0;
3、指针 delete 后内存被释放,内存中的数据被销毁,此内存不该再被访问。但是 delete 后的指针仍然保留着已经释放的动态内存的地址。建议指针 delete 后,赋值为 nullptr。
int main()
int* pi = new int(123);
cout << *pi << "\t" << pi << endl;
delete pi; // 内存被释放,内存中数据被销毁,但是 pi 仍存着这块内存的地址
cout << *pi << "\t" << pi << endl;
pi = nullptr; // 指针地址指空,后续则不能再通过 pi 访问到之前分配的内存
cout << *pi << "\t" << pi << endl;
return 0;
4、指针指向 nullptr 后,再去 delete 不会调用到析构函数。因为此时 指针不再指向分配的内存的地址,通过此指针系统不知道应该回收哪块内存。所以应该先 delete 指针,再去将指针置空。
class A
public:
cout << "A()" << endl;
cout << "~A()" << endl;
int main()
A* pa1 = new A();
pa1 = nullptr;
delete pa1; // 不会调用析构函数,但是应该回收的内存未被回收
A* pa2 = new A();
delete pa2;
delete pa2; // 会多次调用析构函数,可能产生异常
A* pa3 = new A();
delete pa3;
pa3 = nullptr; // 内存已被回收,后续再通过 pa3 访问不到原内存
return 0;
5、只有通过 new 出来的地址,才需要 delete 释放对应的内存。对栈上分配的对象取到的地址,不能通过 delete 释放该内存。
int main()
int i = 10;
int* pi = &i;
delete pi; // 错误,pi 指向的是对象 i 在栈上分配的内存对应的地址,不可通过 delete 释放。
return 0;
6、同一块内存,不能多次释放
int main()
int* p1 = new int(123);
int* p2 = p1; // p2指向和 p1 同一块内存
delete p1;
delete p2; // 错误,p2 指向的内存已经在 delete p1 时被释放。
return 0;
7、用 auto 来 new 一个对象时,若传入的是指针,则返回指针的指针 (诡异的写法,尽量避免)
int main()
int* p = new int(123);
cout << p << endl;
cout << *p << endl;
auto pp = new auto(p); // pp 为 int** 型指针
// 相当于
// int** pp = new int*(p) ;
cout << pp << endl;
cout << *pp << endl;