为什么C ++编译器不能将这个条件布尔赋值作为无条件赋值来优化?

考虑以下function:

void func(bool& flag) { if(!flag) flag=true; } 

在我看来,如果标志有一个有效的布尔值,这将等于无条件设置为true ,如下所示:

 void func(bool& flag) { flag=true; } 

然而gcc和clang都没有这样优化它们 – 都在-O3优化级别生成以下代码:

 _Z4funcRb: .LFB0: .cfi_startproc cmp BYTE PTR [rdi], 0 jne .L1 mov BYTE PTR [rdi], 1 .L1: rep ret 

我的问题是:这只是代码是太特殊的情况下,照顾优化,或者有什么好的理由,为什么这样的优化将是不受欢迎的,因为该flag不是一个参考volatile ? 这似乎是唯一可能的原因是flag在某种程度上可能具有非true false价值,而在阅读时却没有不确定的行为,但我不确定这是否可能。

由于caching一致性考虑,这可能会对程序的性能产生负面影响。 每次func()时写入flag都会使包含的caching线变脏。 无论写入的值是否与写入前的目标地址的位完全匹配,都会发生这种情况。


编辑

hvd提供了另外一个很好的理由来阻止这样的优化。 对于所提出的优化来说,这是一个更有说服力的论点,因为它可能导致不确定的行为,而我的(原始的)答案只涉及性能方面。

经过多一点思考,我可以再提出一个例子,为什么要强制禁止编纂者 – 除非他们能够certificate这种转变对某一特定的情况是安全的 – 而不是引入无条件的写作。 考虑这个代码:

 const bool foo = true; int main() { func(const_cast<bool&>(foo)); } 

如果在func()无条件地写入,这肯定会触发未定义的行为(写入只读内存将会终止程序,即使写入的效果是不可操作的)。

除了Leon的performance之外,

假设flagtrue 。 假设两个线程一直在调用func(flag) 。 在这种情况下写入的函数不会存储任何flag ,所以这应该是线程安全的。 两个线程访问相同的内存,但只能读取它。 无条件设置flagtrue意味着两个不同的线程将写入相同的内存。 这是不安全的,即使正在写入的数据与已经存在的数据相同,这也是不安全的。

我不确定C ++在这里的行为,但是在C中,内存可能会改变,因为如果内存中包含1以外的非零值,那么检查将保持不变,但是检查将更改为1。

但是因为我不太stream利的C ++,我不知道这种情况是否可能。