Item17:以独立语句将newed对象置入智能指针
动态资源管理中,智能指针(如C++11引入的std::unique_ptr
、std::shared_ptr
)是避免内存泄漏的核心工具,但智能指针的使用方式直接影响异常安全性。《Effective C++》Item17“以独立语句将newed对象置入智能指针”(Store newed objects in smart pointers in standalone statements)指出:将new
创建的对象直接作为参数传入智能指针构造函数时,可能因函数参数求值顺序的不确定性导致内存泄漏。本文将解析这一条款,结合C++11智能指针特性,探讨风险根源、案例分析及安全实践。
一、为什么需要独立语句?
函数参数的求值顺序在C++标准中未被严格规定(仅要求参数在函数调用前完成求值,但参数间的顺序不确定),这种不确定性在“new
操作 + 智能指针构造”作为函数参数时,可能引发资源泄漏:
1. 求值步骤的潜在风险
假设存在函数processWidget(std::shared_ptr<Widget> pw, int priority)
,若以processWidget(std::shared_ptr<Widget>(new Widget), getPriority())
形式调用,编译器可能按以下顺序求值:
- 步骤1:执行
new Widget
(分配内存); - 步骤2:调用
getPriority()
(可能抛出异常); - 步骤3:构造
std::shared_ptr<Widget>
(接管资源)。
若步骤2抛出异常,步骤1分配的Widget
对象尚未被智能指针接管,导致内存泄漏。
2. C++11智能指针的构造特性
std::shared_ptr
和std::unique_ptr
的构造函数对原始指针参数是explicit
的(禁止隐式转换),必须显式构造。但这仅避免了隐式转换风险,无法解决参数求值顺序导致的泄漏——只要new
与智能指针构造在同一语句的参数中,就可能触发上述问题。
例如,异常导致泄漏的场景:
#include <memory>void