引子:C++中如何有效管理分配在堆中的对象
考虑以下函数:
问题: delete pInv一定会被执行吗?当然不是!
随便列举几种情形。有可能在这个函数的 "..." 部分的某处有一个提前出现的 return 语句。如果这样一个 return 执行了,控制流程就再也无法到达 delete 语句。还可能发生的一个类似情况是如果 createInvestment 的使用和删除在一个循环里,而这个循环以一个 continue 或 goto 语句提前退出。还有,"..." 中的一些语句可能抛出一个异常。如果这样,控制流程不会再到达那个 delete。无论那个 delete 被如何跳过,我们泄漏的不仅仅是容纳 investment 对象的内存,还包括那个对象持有的任何资源。还有,为了对软件进行维护,一些人可能会在没有完全把握对这个函数的资源管理策略的其它部分的影响的情况下增加一个 return 或 continue 语句。尤有甚者,f 的 "..." 部分可能调用了一个从不惯于抛出异常的函数,但是在它被“改良”后突然这样做了。依赖于 f 总能到达它的 delete 语句根本靠不住。
如何保证分配在堆上的对象一定可以释放?
方法一:使用smart pointer,如TR1的shared_ptr。使用它们的析构函数确保资源被释放。因为当一个对象被销毁时(例如,当一个对象离开其活动范围)会自动调用析构函数,无论控制流程是怎样离开一个块的,资源都会被正确释放。
void f() { Investment *pInv = createInvestment(); // call factory function ... // use pInv delete pInv; // release object } |
问题: delete pInv一定会被执行吗?当然不是!
随便列举几种情形。有可能在这个函数的 "..." 部分的某处有一个提前出现的 return 语句。如果这样一个 return 执行了,控制流程就再也无法到达 delete 语句。还可能发生的一个类似情况是如果 createInvestment 的使用和删除在一个循环里,而这个循环以一个 continue 或 goto 语句提前退出。还有,"..." 中的一些语句可能抛出一个异常。如果这样,控制流程不会再到达那个 delete。无论那个 delete 被如何跳过,我们泄漏的不仅仅是容纳 investment 对象的内存,还包括那个对象持有的任何资源。还有,为了对软件进行维护,一些人可能会在没有完全把握对这个函数的资源管理策略的其它部分的影响的情况下增加一个 return 或 continue 语句。尤有甚者,f 的 "..." 部分可能调用了一个从不惯于抛出异常的函数,但是在它被“改良”后突然这样做了。依赖于 f 总能到达它的 delete 语句根本靠不住。
如何保证分配在堆上的对象一定可以释放?
方法一:使用smart pointer,如TR1的shared_ptr。使用它们的析构函数确保资源被释放。因为当一个对象被销毁时(例如,当一个对象离开其活动范围)会自动调用析构函数,无论控制流程是怎样离开一个块的,资源都会被正确释放。