跳转到内容

更多 C++ 惯用法/函数中毒

来自 Wikibooks,开放书籍,开放世界

函数中毒

[编辑 | 编辑源代码]

隐藏或禁止使用某些函数,支持更好的替代方案。

通常,在与具有 C 或 C++11 前接口的库交互时,由于现代 C++ 表达能力更强,因此隐藏(对正在项目中工作的人员来说)所有(或仅仅是许多)分配内存并返回原始指针(如 T*)的函数,并用更友好的 RAII 方法(如 unique_ptr)替换它们非常方便。

解决方案和示例代码

[编辑 | 编辑源代码]
// header of external library

foo* create_foo();
foo_destroy(foo*);

// our header, with our enhanced version

struct foo_deleter {
    void operator()(foo* h) {
        // foo_destroy provided by the 3rd party library as function, macro, ...
        foo_destroy(h);
    }
};
using unique_foo = std::unique_ptr<foo, foo_deleter>;


inline unique_foo create_unique_foo() {
    // we do not have poisoned create_foo yet!
    return unique_foo{create_foo()};
}
#pragma GCC poison create_foo
// from now on, no-one can use create_foo again!
// at least with GCC and clang

禁止函数的指南

如果函数 g 是库 L 中函数 f 的严格替换,那么

  • g 提供了比 f 更明显的优势(例如将析构函数中的析构器替换为手动调用)
  • g 可以作为 f 的直接替换,这意味着
    • 它可以在不编写多于一行没有明显缺点的粘合代码的情况下与库 L 交互
    • 在代码库中将 f 更新为 g 是一个简单的操作(使用更改所有出现或简单的查找和替换)
    • 删除 f 的成本不太高
  • gf 相比没有任何缺点,这意味着
    • 它与 f 相比没有添加任何可衡量的运行时开销
    • 它没有添加任何新的依赖项
    • 它不能降低类型安全性、异常安全性或线程安全性
    • 它不能引入新的编程错误类型
  • gf 相比不会降低可读性或隐藏意图,这意味着
    • 不需要记录 g 的作用,因为它应该与 f 一样,只有在那些对每个人都不清楚的情况下才需要记录其优点。

因此,如果 gf 的严格替换,那么可以在代码库中禁止 f

已知用途

[编辑 | 编辑源代码]

用具有改进功能的函数替换不能删除的函数(例如,如果它是外部库的一部分)。

[编辑 | 编辑源代码]

参考文献

[编辑 | 编辑源代码]
华夏公益教科书