在C ++中“毒害函数”是什么意思?


96

在斯科特·舒尔(Scott Schurr)在CppCon上的演讲“介绍constexpr”结束时,他问“有没有办法毒害某个功能”?然后,他解释说可以通过以下方式(尽管以非标准方式)完成此操作:

  1. 把一个throwconstexpr功能
  2. 宣布未解决 extern const char*
  3. 引用未解决externthrow

我感觉自己在这里有些深奥,但我很好奇:

  • “使功能中毒”是什么意思?
  • 他概述的技术的意义/用处是什么?

1
从未听说过该术语,请举一个简洁的例子进行说明!
πάνταῥεῖ

6
@πάνταῥεῖ,我刚才澄清了。这个术语“在小圈子中广为人知”
SergeyA 2015年

4
他正在谈论确保constexpr在编译时评估对函数的每次调用。
TC

@TC对-他提到constexpr可以在编译时或运行时使用函数。因此,这是强制执行此操作的方法,以便您无法在运行时使用它?什么时候有用?
sudo make install

3
尤其是在C ++ 11中,constexpr由于约束条件,函数通常不是最有效的实现,因此可能不希望在运行时对其进行求值。或者,也许是错误情况(如他的示例)。
TC

Answers:


106

通常,它指的是使函数不可用,例如,如果要禁止在程序中使用动态分配,则可以“中毒”该malloc函数,使其无法使用。

在视频中,他以一种更特定的方式使用它,如果您阅读了他谈到中毒该功能时显示的幻灯片,则可以清楚地看到它,其中说“一种仅强制编译时间的方法?”

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

throwconstexpr函数中允许使用表达式,只要在该函数的编译时调用中从未达到过该表达式即可(因为您不能在编译时抛出异常,所以它是一种固有的动态操作,例如分配内存)。因此,引用未定义符号的throw表达式将不会在编译时调用期间使用(因为编译失败),并且无法在运行时使用,因为未定义符号会导致链接器错误。

由于未定义的符号在函数的编译时调用中不是“奇特使用的”,因此实际上编译器不会创建对该符号的引用,因此可以确定未定义的符号。

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

可能有用的原因之一是某些操作的编译时版本效率不高。constexpr函数中允许的表达式种类有一些限制(尤其是在C ++ 11中,在C ++ 14中已删除了一些限制)。因此,您可能有两种版本的函数来执行计算,一种是最佳版本,但使用的是constexpr函数中不允许使用的表达式,而另一种版本是有效的constexpr函数,但是如果在运行时调用,性能会很差-时间。您可以毒化次优版本,以确保它永远不会用于运行时调用,从而确保更有效的版本(非constexpr)用于运行时调用。

注意:在编译时使用constexpr函数的性能并不是很重要,因为它始终没有运行时开销。它可能会使编译器执行额外的工作,从而减慢编译速度,但不会增加运行时性能成本。


1
我确实读过幻灯片的文字,但没有看到与他所用术语的联系。显而易见,您已经解释了它,但当时我没有看到它。非常感谢您的出色回答-我很喜欢这个网站。
sudo make install

@PravasiMeet,问您自己的问题,不要劫持别人对其他问题的评论。一个简单的解决方案是将其定义为在每个翻译单元中都已删除,或者将其替换为引用未定义符号的自己定义。
乔纳森·威克利

17

“中毒”标识符意味着“中毒”之后对标识符的任何引用都是硬编译器错误。例如,此技术可用于硬弃用(不推荐使用功能,请勿使用!)。

传统上,在GCC中对此有一种语用说明:#pragma GCC poison


1
是的,但是在那个谈话中所使用的意义并不完全。
TC

@TC,好的,我可能应该在回答之前看一下它:)
SergeyA 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.