13.8 内存管理
动态分配和释放堆内存的代价比较昂贵。从性能角度来讲,使用不需要显式管理的内存所产生的代价要低得多。被定义成局部变量的对象存放于堆栈上。该对象所占用的堆栈空间是为相应函数预留的堆栈空间的一部分,该对象被定义在这个函数范围内。局部对象的一种办法是使用new()和delete()来分配和释放堆内存:
- void f()
- {
- X *xPtr = new X;
- ...
- delete xPtr;
- }
另一种性能更好的选择是定义类型为X的局部对象:
- void f ()
- {
- X x;
- ...
- } // 不需要释放x的内存
在后一种实现中,对象x驻留在堆栈上,因而不需要事先为其分配内存,也不需要在函数退出时释放内存。当f()返回时,堆栈内存会自动释放,这样就避免了调用new()和delete()的巨大代价。
成员数据中也存在类似的问题。但这次不是堆和堆栈内存之间的问题,而是选择将指针还是整个对象嵌入到包含对象中的问题:
- class Z {
- public:
- Z() : xPtr (new X) {... }
- ~Z() {delete xPtr; ... }
-
- private:
- X *xPtr;
- ...
- };
在构造函数中调用new()和在析构函数中调用delete()所产生的开销明显地增加了对象Z的代价。我们可以通过在Z中嵌入对象X来消除内存管理的代价:
- class Z {
- public:
- Z() {... }
- ~Z() {... }
-
- private:
- X x;
- ...
- };
通过将X对象指针替换为X对象,我们用多态使用该成员变量换取了性能。当然,如果真的需要这种灵活性,那么这种优化是不合适的。再次说明一下:性能就是一种折中的结果。