资源泄漏风险分析
示例一:
// 1. 唤起 三次构造函数 // 2. 无法藉由参数进行初始化,因此 Complex 需要有默认构造函数 Complex *pca = new Complex[3]; ... ... // 3. 唤起三次析构函数 delete[] pca;
示例二:
// 1. 唤起 三次构造函数 // 2. 无法藉由参数进行初始化,因此 string需要有默认构造函数 string *psa = new string[3]; ... ... // 3. 唤起一次析构函数 delete psa;
问:没对数组里面的每个对象调用析构函数(示例二),会有什么影响呢?
- 对 class without pointer 可能没有影响(不会有资源泄露)
- 对 class with pointer 通常有影响 (会有资源泄露)
说明:
- 示例一中,当
delete pca;
pca 指向的全部内存空间将会被安全释放 - 示例二中,当
delete psa;
psa 指向的全部内存空间将会被安全释放,但因为 string 实现中包含指针指向一段堆空间中申请的内存空间以存储字符串,而数组元素数量的析构函数未被全部对应调用,导致字符串空间未被释放,因此会造成资源泄露
- 示例一中,当
总结
- new, delete ; new [], delete [] 需要配对使用
数组元素的构造与析构顺序
#include <iostream>
using namespace std;
class A
{
public:
int id;
A() : id(0) {
cout << "default ctor.this=" << this << " id=" << id << endl;
}
A(int i) : id(i) {
cout << "default ctor.this=" << this << " id=" << id << endl;
}
~A() {
cout << "dtor.this=" << this << " id=" << id << endl;
}
};
constexpr size_t size = 3;
int main()
{
// A 必须有默认构造函数
// 默认构造函数调用三次,[0] 先于 [1] 先于 [2]
A *buf = new A[size];
A* tmp = buf;
cout << "buf=" << buf << " tmp=" << tmp << endl;
for (size_t i=0; i < size; ++i) {
// placement new: 在指定的地址构造对象
new (tmp++)A(i);
}
cout << "buf=" << buf << " tmp=" << tmp << endl;
// 析构函数三次被调用(次序逆反,[2] 先于 [1] 先于 [0])
delete[] buf;
return 0;
}
总结
- 数组中元素的构造顺序与析构顺序相反
在内存块中的数组大小
(array size, in memory block)
int *pi = new int[10];// from heap but not stack
cout << sizeof(pi); // 4
delete pi;
int ia[10]; // from stack but not heap
cout << sizeof(ia); // 40
- vc6 中的内存布局(后续将详细讲解)
class Demo {
public:
int a;
omt
};
==> (32 + 4) + 4 + 36 + (4 * 2) = 84
==> 84 + 12 = 96 = 60H
==> 60H + 1H = 61H
说明 [后续将详细讲解]
- 84 bytes:
- 32byte : Debugger Header
- 4 byte : no man land
- 4 byte : 对应图中3,标记数组元素数量
- 36byte : Demo object
4 * 2 byte : up cookie + down cookie
- 60H bytes
16 字节对齐
- 61H bytes
- 一个字节标记当前内存是否被使用
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。