更多 C++ 惯用法/函数中毒
外观
隐藏或禁止使用某些函数,支持更好的替代方案。
通常,在与具有 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
的成本不太高
g
与f
相比没有任何缺点,这意味着- 它与
f
相比没有添加任何可衡量的运行时开销 - 它没有添加任何新的依赖项
- 它不能降低类型安全性、异常安全性或线程安全性
- 它不能引入新的编程错误类型
- 它与
g
与f
相比不会降低可读性或隐藏意图,这意味着- 不需要记录
g
的作用,因为它应该与f
一样,只有在那些对每个人都不清楚的情况下才需要记录其优点。
- 不需要记录
因此,如果 g
是 f
的严格替换,那么可以在代码库中禁止 f
。
用具有改进功能的函数替换不能删除的函数(例如,如果它是外部库的一部分)。