Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 迈尔斯';与[[gnu::pure]]一起使用的singleton有UB吗?_C++_Gcc_Clang_Language Lawyer - Fatal编程技术网

C++ 迈尔斯';与[[gnu::pure]]一起使用的singleton有UB吗?

C++ 迈尔斯';与[[gnu::pure]]一起使用的singleton有UB吗?,c++,gcc,clang,language-lawyer,C++,Gcc,Clang,Language Lawyer,以下代码是否有未定义的行为 [[ gnu::pure ]] static const MyClass &myClass() noexcept { static const MyClass s_myClass; return s_myClass; } 根据,纯属性适用于除返回值外没有任何影响的函数,该返回值仅取决于参数和/或全局变量 一方面,该函数除了返回值之外没有任何可观察的效果,并且总是返回相同的值。因此,优化对该函数的多次调用是完全安全的。这就是我认为的pure属性

以下代码是否有未定义的行为

[[ gnu::pure ]]
static const MyClass &myClass() noexcept
{
    static const MyClass s_myClass;
    return s_myClass;
}
根据,纯属性适用于除返回值外没有任何影响的函数,该返回值仅取决于参数和/或全局变量

一方面,该函数除了返回值之外没有任何可观察的效果,并且总是返回相同的值。因此,优化对该函数的多次调用是完全安全的。这就是我认为的
pure
属性的作用

另一方面,此函数需要在第一次调用时构造
MyClass
对象。这包括调用
MyClass
构造函数并将隐式is initialized标志设置为true。这可以算作返回值之外的效果(尽管从外部看不到)


此代码适用于
gcc
,但
clang
优化了
MyClass
构造部分,并使
MyClass()
返回未初始化的对象。一位
clang
开发人员坚持认为这是因为未定义的行为


请参阅此错误报告:(注意,它说的是
gnu::const
,但使用
gnu::pure
会产生相同的结果)。

文档包含以下说明:

有趣的非纯函数是具有无限循环的函数,或者那些依赖于易失性内存或其他系统资源的函数,它们可能在两个连续调用之间发生变化

由于静态变量构造函数和invisible is initialized标志都在函数调用之间更改内存,这表明函数不是纯函数

pure
的文档还注意到它类似于
const
。在
pure
下,它没有明确说明这一点,但在
const
下,它说:

同样,调用非
const
函数的函数通常不能是
const


由于您的函数调用的构造函数不是
常量
,因此它似乎违反了属性的规则。但是请看下面的评论。

我认为静态局部变量的初始化有两个潜在问题

:

如果初始化通过抛出异常退出,则初始化未完成,因此下次控件进入声明时将再次尝试初始化

这意味着对这个函数的连续调用可能有很多不同的行为——第一个抛出,第二个不抛出。这似乎违背了纯的精神和意图

:

如果控件在初始化变量时并发输入声明,则并发执行应等待初始化完成


这意味着对主体的解释必须基于功能的内在状态-需要锁定等。这似乎也违反了
pure

的精神和意图,我们所要做的就是gcc属性
pure
的文本,来自:

纯洁的

许多函数除了返回值之外没有任何效果,它们的返回值仅取决于参数和/或全局变量。像算术运算符一样,对此类函数的调用可以进行公共子表达式消除和循环优化。这些函数应该用pure属性声明。比如说,

int square (int) __attribute__ ((pure));
假设函数square的调用次数比程序所说的要少

纯函数的一些常见示例是strlen或memcmp。有趣的非纯函数是具有无限循环的函数,或者那些依赖于易失性内存或其他系统资源的函数,它们可能在两个连续调用之间发生变化(例如多线程环境中的feof)

与const属性相比,pure属性对函数的定义施加了类似但更宽松的限制:它允许函数读取全局变量。诊断使用pure和const属性装饰相同的函数

这没有典型的标准文本那么专业,但这是我们必须解决的问题

我将列出我读到的测试:

  • 除了返回值之外没有其他效果
  • 返回值仅取决于参数和/或全局变量
  • 调用可以像算术运算符一样进行公共子表达式消除/循环优化
  • 假设函数的调用次数比程序所说的少是安全的
其核心是消除重复呼叫,而不是所有呼叫

不纯粹事物的例子:

  • 无限循环
  • 依赖于易失性内存或其他系统资源
  • 可能在两次连续呼叫之间发生变化
在这个描述中,没有任何地方提到“您可以消除对这个函数的第一次调用”——它说您可以消除对这个函数的重复调用

Clang的“优化”导致函数体永远不会运行。
[[gnu:pure]]
的目的是删除重复调用,而不是消除所有调用。因此,叮当显然是错误的


可能有一些属性可以调用
pure
,以允许clang进行优化,但
[[gnu:pure]]
不是该属性。

[[gnu:pure]]
在该语言下无效。您可能需要添加特定于编译器的信息。@Yakk,谢谢,我已经更新了问题。您不能“触发未定义的行为”。未定义的行为不是事件或动作。我们说以某种方式编写的程序具有未定义的行为;也就是说,它的行为是未定义的。进一步说,程序是否有未定义的行为是由C++标准决定的,它对代码< >没有任何知识[[GN ] ]。