Kan*_*ane 3 c++ gcc clang language-lawyer
以下代码是否具有未定义的行为?
[[ gnu::pure ]]
static const MyClass &myClass() noexcept
{
static const MyClass s_myClass;
return s_myClass;
}
Run Code Online (Sandbox Code Playgroud)
根据gcc docs,该pure属性适用于除返回值之外没有任何影响的函数,此返回值仅取决于参数和/或全局变量.
一方面,除了返回值之外,此函数没有任何可观察的效果,并且它总是返回相同的值.因此,优化多次调用此函数是完全安全的.这是我认为pure属性的用途.
另一方面,此函数需要MyClass在第一次调用时构造对象.这包括调用MyClass构造函数并将隐式的is-initialised标志设置为true.这可以算作除返回值之外的效果(尽管从外部看不到).
此代码可以工作gcc,但会clang优化MyClass构造部分并使myClass()返回成为未初始化的对象.一个clang开发商坚称这是因为不确定的行为.
请参阅此错误报告:https://bugs.llvm.org/show_bug.cgi?id = 36750(注意它说gnu::const,但使用gnu::pure产生相同的结果).
我认为初始化静态局部变量有两个潜在的问题.
第一:
如果通过抛出异常退出初始化,则初始化未完成,因此下次控制进入声明时将再次尝试初始化
这意味着对此函数的连续调用可能会有很多不同的行为 - 第一次抛出而第二次不抛出.这似乎违反了精神和意图pure.
第二:
如果控制在初始化变量时同时进入声明,则并发执行应等待初始化完成.
这意味着身体的解释必须基于功能的内在状态 - 需要锁定等.这似乎也违背了精神和意图pure.
我们所要做的只是gcc属性的文本pure,从这里:
纯
除返回值外,许多函数都没有效果,它们的返回值仅取决于参数和/或全局变量.对算术运算符的调用可以对这些函数的调用进行公共子表达式消除和循环优化.应使用pure属性声明这些函数.例如,
Run Code Online (Sandbox Code Playgroud)int square (int) __attribute__ ((pure));他说,假设的函数square可以安全地调用比程序所说的更少的次数.
纯函数的一些常见示例是strlen或memcmp.有趣的非纯函数是具有无限循环的函数或取决于易失性存储器或其他系统资源的函数,其可以在两个连续调用(例如多线程环境中的feof)之间改变.
纯属性对函数的定义施加与const属性类似但更宽松的限制:它允许函数读取全局变量.诊断出使用pure和const属性装饰相同的函数.
这不像典型的c ++标准文本那样技术性,但这是我们必须使用的.
我将列出我读过的测试:
其核心是消除重复呼叫,而不是所有呼叫.
不纯粹的事情的例子:
在这个描述中没有说它"你可以消除对这个函数的第一次调用" - 它说你可以消除对该函数的重复调用.
Clang的"优化"导致函数体从未运行.目的[[ gnu:pure ]]是删除重复的呼叫,而不是消除所有呼叫.因此,铿锵显然是错的.
您可以调用的属性可能pure允许优化clang正在执行,但[[gnu:pure]]不是该属性.