"poison a function" 在 C++ 中是什么意思?

What does it mean to "poison a function" in C++?

在 Scott Schurr 演讲的最后 "Introducing constexpr" at CppCon,他问 "Is there a way to poison a function"?然后他解释说这可以通过以下方式完成(尽管以非标准方式):

  1. throw 放入 constexpr 函数中
  2. 声明未解决extern const char*
  3. 引用 throw
  4. 中未解决的 extern

我觉得我有点不知所云,但我很好奇:

'Poisoning' 标识符意味着在 'poisoning' 之后对标识符的任何引用都是硬编译器错误。例如,此技术可用于硬弃用(功能已弃用,永远不要使用它!)。

传统上在 GCC 中有一个 pragma:#pragma GCC poison

一般是指使某个功能无法使用,例如如果你想禁止在程序中使用动态分配,你可以 "poison" malloc 函数,这样它就不能被使用了。

在视频中,他以更具体的方式使用它,如果您阅读他谈到中毒功能时显示的幻灯片,就会清楚这一点,上面写着 "A way to force compile-time only?"

所以他在谈论 "poisoning" 使其在 运行 时间不可调用的函数,因此它 可在常量表达式中调用。该技术是在函数中有一个在编译时上下文中调用时永远不会采用的分支,并使该分支包含会导致错误的内容。

constexpr 函数中允许使用 throw 表达式,只要在函数的编译时调用期间永远不会达到它(因为您不能在编译时抛出异常,这是一个固有的动态操作,如分配内存)。因此,引用未定义符号的 throw 表达式将不会在编译时调用期间使用(因为那样会编译失败)并且不能在 运行 时使用,因为未定义符号会导致链接器错误。

因为未定义的符号在函数的编译时调用中不是"odr-used",实际上编译器不会创建对该符号的引用,所以它是未定义的。

有用吗?他正在演示 如何 做这件事,并不一定是说这是个好主意或广泛有用。如果您出于某种原因需要这样做,那么他的技术可能会解决您的问题。如果您不需要它,则无需担心。

可能 有用的一个原因是当某些操作的编译时版本没有达到预期的效率时。 constexpr 函数中允许的表达式类型有限制(特别是在 C++11 中,一些限制在 C++14 中被移除)。因此,您可能有两个版本的函数来执行计算,一个是最优的,但使用了 constexpr 函数中不允许的表达式,另一个是有效的 constexpr 函数,但如果在 运行-时间。您可以毒害次优版本以确保它永远不会用于 运行 次调用,确保更高效(非 constexpr)版本用于 运行 次调用。

N.B。在编译时使用的 constexpr 函数的性能并不重要,因为它无论如何都没有 运行 时间开销。它可能会让编译器做额外的工作来减慢你的编译速度,但它不会有任何 运行 时间的性能成本。