liangbm3's blog

Back

这是 Effective C++ 的第 15 个条款,Provide access to raw resources in resource-managing classes,中文翻译为:在资源管理类中提供对原始资源的访问。

这个条款解决了一个非常实际的问题:我们已经接受了 RAII 是管理资源的最佳方式,但我们所写的代码需要和大量已有的、只认“原始资源”的 API 交互。例如:

std::shared_ptr<Investment> pInv(createInvestment());
int daysHeld(const Investment* pi); // 一个只接受裸指针的 API
daysHeld(pInv); // 编译错误!类型不匹配,pInv 不是 Investment*
cpp

RAII 对象(pInv)封装了并管理着原始资源( Investment* 指针),但它本身并不是那个原始资源。因此,RAII 类必须提供一个“出口”,允许外界在需要时能够访问到它内部封装的那个原始资源。在书中,作者提到了两种常见的做法:

  • 显式转换:提供一个专门的成员函数(通常命名为 get),让用户明确地调用它来获取原始资源。std::shared_ptrstd::unique_ptr 都提供了 get() 成员函数。
    daysHeld(pInv.get()); // 正确!调用 get() 获取裸指针
    cpp
    对于我们自定义的 Font 类,也可以添加一个 get() 方法:
    class Font {
    public:
        FontHandle get() const { return f; } // 显式转换函数
        // ...
    private:
        FontHandle f;
    };
    
    Font myFont(getFont());
    changeFontSize(myFont.get(), newSize); // 用户需要明确调用 .get()
    cpp
    • 优点:代码意图非常明确。任何看到 .get() 的人都知道这里正在从一个管理类中取出其原始资源。这降低了误用的风险。
    • 缺点:用户必须时刻记着在需要原始资源的地方调用 .get()
  • 隐式转换:通过 C++ 的类型转换运算符,可以让类对象可以自动地、不经指明地转换为原始资源类型。实现的方法是在类中定义一个类型转换运算符 operator T(),其中 T 是你希望转换的目标类型。
    class Font {
    public:
        operator FontHandle() const { return f; } // 隐式转换函数
        // ...
    };
    
    Font myFont(getFont());
    changeFontSize(myFont, newSize); // 非常自然!myFont 自动转换为 FontHandle
    cpp
    • 优点:用户代码写起来非常自然流畅,就像直接使用原始资源一样。
    • 缺点:方便是有代价的。隐式转换可能在你不期望的时候发生,导致难以发现的 bug。书中举了一个绝佳的例子:
      Font f1(getFont());
      FontHandle f2 = f1;
      cpp
      程序员的意图可能是想创建一个 Font 的副本,但这里实际上触发了 operator FontHandle(),创建了一个原始句柄 f2。当 f1 被销毁时,它会释放字体资源,而 f2 此时就变成了一个悬空句柄,再使用它就会导致程序崩溃或未定义行为。
      智能指针的 operator*operator-> 也是一种隐式转换,但它们被设计得相对安全,因为它们返回的是对象本身或其成员的引用/指针,而不是资源句柄的副本。

总的来说,安全性通常比便利性更重要,因此:

  • 首选显式转换 (get 方法)。它让代码的意图更加清晰,并且可以有效避免由意想不到的类型转换所引起的严重错误。
  • 谨慎使用隐式转换。虽然它能让客户代码更漂亮,但它带来的风险(如上述的悬空句柄问题)往往得不偿失。只有在确定这种转换在所有情况下都是安全且符合直觉时,才应该考虑提供它。
Effective C++: 在资源管理类中提供对原始资源的访问
https://liangbm3.site/blog/effective-c-zai-zi-yuan-guan-li-lei-zhong-ti-gong-dui-yuan-shi-zi-yuan-de-fang-wen
Author liangbm3
Published at 2025年10月20日
Comment seems to stuck. Try to refresh?✨