一. 内容
-
令人惊讶的是,即使我们使用对象管理资源,下面代码仍存在泄漏资源。
inline Resource* GetResource() { return new Resource(1); } inline void OtherProgress(std::shared_ptr<Resource> Resource, int Priority) {} inline void UseResource() { OtherProgress(std::shared_ptr<Resource>(GetResource()), GetPriority(100)); }
-
编译器在产出 OtherProgress 调用码之前,需要
核算每一个被传递的实参
。上述第二实参只是一个单纯的返回优先级函数,但是第一实参由两部分组成:- 执行 new Resource 表达式
- 调用 shared_ptr 构造函数
这意味着在调用 OtherProgress 之前,要做这三件事。
但是编译器并不保证这三件事情的次序
。这和其他语言如Java,C#不同,那两种语言总是以特定的次序完成函数的核算。如果编译器为了更高效的代码
,那么它们的调用次序不一定是按实参的次序。可能:- 执行new Resource表达式
- 调用GetPriority函数
- 调用shared_ptr构造函数
假如是按这种方式,如果对调用 GetPriority 函数时出现异常,会发生什么事情,new Resource 返回的资源尚未置入 shared_ptr 智能指针,也就是未进入我们防卫资源泄漏的武器。
这种由于核算实参次序导致的问题可以很简单的被避免:使用分离语句,先创建Resource,再调用OtherProgress。inline void OtherProgress(std::shared_ptr<Resource> Resource, int Priority) {} inline void UseResource() { const std::shared_ptr<Resource>ResourcePointerOne(GetResource()); OtherProgress(ResourcePointerOne, 100); }
这样,编译器不能再重新排列这些跨语句的各项操作
,从而促使事件向我们期望的方向发展。
二. 总结
- 以独立语句将 newed 对象存储于(置入)智能指针内。如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄漏。