C++ 写记忆是一种可以观察到的行为吗?

C++ 写记忆是一种可以观察到的行为吗?,c++,c++11,C++,C++11,我查看了标准,但没有发现任何迹象表明,简单地向内存中写入将被视为可观察的行为。如果不是,那就意味着编译后的代码实际上不需要写入该内存。如果编译器选择优化这种访问,那么涉及映射器内存或共享内存的任何内容都可能无法工作 1.9-8似乎定义了非常有限的可观察行为,但表明实施可能定义更多。有人能比任何高质量的编译器都认为修改内存是一种可观察的行为吗?也就是说,它可能不能保证原子性或有序性,但可以保证数据最终会被写入 那么,我是否忽略了标准中的某些内容,或者写入内存仅仅是编译器决定要做的事情 来自当前或C

我查看了标准,但没有发现任何迹象表明,简单地向内存中写入将被视为可观察的行为。如果不是,那就意味着编译后的代码实际上不需要写入该内存。如果编译器选择优化这种访问,那么涉及映射器内存或共享内存的任何内容都可能无法工作


1.9-8似乎定义了非常有限的可观察行为,但表明实施可能定义更多。有人能比任何高质量的编译器都认为修改内存是一种可观察的行为吗?也就是说,它可能不能保证原子性或有序性,但可以保证数据最终会被写入

那么,我是否忽略了标准中的某些内容,或者写入内存仅仅是编译器决定要做的事情


来自当前或C++0x标准的语句是好的。请注意,我不是说通过函数访问内存,我指的是直接访问,例如将数据写入指针(可能通过mmap或另一个库函数检索)。

这种事情就是
volatile
存在的目的。否则,写在记忆中而从不明显地从中读取是不可观察的行为。然而,在一般情况下,优化器不可能证明您除了在相对琐碎的示例中之外从未读过它,因此这通常不是问题


有人能比任何高质量的编译器都认为修改内存是一种可观察的行为吗

不,Volatile是用来做标记的。但是,即使在添加volatile限定符之后,您也无法完全信任编译器,至少正如2008年的一篇论文所述:

编辑:

来自C标准(不是C++)

如果实际实现可以推断表达式的值没有被使用,并且没有产生所需的副作用(包括调用函数或访问易失性对象引起的副作用),则不需要计算表达式的一部分


我对C99的理解是,除非指定
volatile
,否则实际访问变量的方式和时间是由实现定义的。如果指定
volatile
限定符,则代码必须根据抽象机器的规则工作

本标准中的相关部分为:
6.7.3类型限定符
volatile
说明)和
5.1.2.3程序执行
(抽象机器定义)

一段时间以来,我知道许多编译器实际上都有试探法来检测何时应该重新读取变量以及何时可以使用缓存副本。Volatile向编译器表明,对变量的每次访问实际上都应该是对内存的访问。如果没有volatile,编译器似乎可以自由地从不重新读取变量

顺便说一句,将访问权包装在函数中并不会改变这一点,因为即使没有内联的函数也可能由编译器在当前编译单元中内联

从你下面的问题:


假设我在堆上使用一个数组(未指定其分配位置), 我用这个数组来进行计算(临时空间)。这个 优化器发现它实际上不需要任何空间,因为它 可以严格使用注册表。编译器是否仍然编写了 内存中的临时值

根据下面的m选项:

这不是保证,也不太可能。考虑一个静态单 分配优化器。这将计算出每个可能的写入/读取 然后分配寄存器以优化这些依赖关系。 作为一种副作用,任何没有(可能)读取的写入操作 完全不创建依赖项,并且已消除。在你的例子中 (“严格使用寄存器”)优化器已满足所有写入/读取要求 依赖于寄存器,因此它根本不会写入内存。全部的 读取生成正确的值,因此这是一个正确的优化


我理解volatile,但这也意味着编译器除了编写数据之外还有其他限制。如果必须将任何共享内存声明为易失性的话,这似乎太过分了——特别是当您使用另一种方式来防止数据争用时。因此,如果指针来自库函数,编译器无法对如何使用它做出任何假设。这是否足以迫使编译器实际编写数据?@edA qa mort-ora-y:差不多,是的。记住,优化器必须绝对地证明你从不读取数据,如果它不知道它来自哪里,那几乎是不可能的。@ EDA QA MalT-ORA-Y:考虑<代码> *(GETPOTIN())=0;出口(0)。优化器显然可以消除写操作。此外,优化器还可能延迟实际写入,这是很常见的。@MSalters,实际上我不同意这一点。优化器将不知道对退出时的
或pthread cleanup处理程序的任何调用。所以它不知道是否读过0。在那句话中,“访问易失性对象”是“需要的副作用”的一个例子,而不是“表达式的一部分”。编译器无法更改
volatile
访问的语义。是的,我知道这一点。这篇文章展示了编译器中的bug,我并不是说diregarding volatile是标准的。我几周前读过这篇文章,可能是我的大脑关注这个话题的原因。我理解这一点。我的具体问题是编译器是否必须将数据写入内存。也就是说,尽管它可能决定不重读,或以不同的顺序写入,但写入内存是否最终会成为写入该内存?@edA:这听起来像是一个循环论证。请重新措辞。假设我在堆上使用了一个数组(未指定其分配位置),并使用该数组执行计算(临时空间)。优化器发现它实际上不需要任何空间,因为它可以严格使用寄存器。编译器是否仍将临时值写入内存?@edA qa mort-ora-y: