文章目录
- 条款 15:在资源管理类中提供对原始资源的访问
- 核心思想
- 原始资源的访问方式
- 标准库中的实现示例
- 设计建议
- 总结
条款 15:在资源管理类中提供对原始资源的访问
核心思想
- 为什么需要访问原始资源?
在使用 RAII(Resource Acquisition Is Initialization)类时,有些 API 需要直接访问原始资源(raw resources)。 - 解决办法
RAII 类应提供一种方法,让用户可以安全地访问其管理的原始资源。
原始资源的访问方式
-
显式转换
- 提供一个显式的成员函数(如
get
),返回所管理的原始资源。 - 安全性较高,因为用户需要明确调用此函数。
示例:显式转换
class ResourceGuard { private:Resource* resource; public:explicit ResourceGuard(Resource* res) : resource(res) {}~ResourceGuard() { delete resource; }Resource* get() const { return resource; } // 显式访问原始资源 };
- 提供一个显式的成员函数(如
-
隐式转换
- 重载类型转换操作符,允许 RAII 类对象隐式转换为原始资源。
- 使用方便,但可能带来安全风险,尤其是在隐式转换可能导致意外的行为时。
示例:隐式转换
class ResourceGuard { private:Resource* resource; public:explicit ResourceGuard(Resource* res) : resource(res) {}~ResourceGuard() { delete resource; }operator Resource*() const { return resource; } // 隐式访问原始资源 };
标准库中的实现示例
-
std::shared_ptr
和std::unique_ptr
的get
成员函数
它们通过get
提供显式的原始资源访问。示例:
get
成员函数std::shared_ptr<Resource> sp(new Resource()); Resource* raw = sp.get(); // 显式访问原始资源
-
隐式转换示例(
std::unique_ptr
的operator bool
)
它允许 RAII 类对象在布尔上下文中隐式转换。示例:布尔上下文隐式转换
std::unique_ptr<Resource> up(new Resource()); if (up) { // RAII 对象非空 }
设计建议
-
优先选择显式转换
显式转换通过成员函数(如get
)提供资源访问,避免意外的隐式转换,提升代码安全性和可读性。 -
在必要时提供隐式转换
如果隐式转换可以显著提升代码的易用性且不会带来安全风险,可以实现隐式转换操作符。 -
确保资源访问的合法性
提供的资源访问方法应在 RAII 对象生命周期内确保资源的有效性,避免悬挂指针等问题。
总结
- RAII 类应该提供一种安全的方式,让用户访问其管理的原始资源。
- 显式转换(如
get
)通常是首选,因为它安全且明确。 - 在特定场景下可以提供隐式转换,但需谨慎处理以避免意外的行为。