在C++中捕获lambdas的全局引用是否会抑制别名优化?

Nia*_*las 5 c++ lambda strict-aliasing compiler-optimization c++11

在为竞争条件工作时调试一些代码时出现了一个问题:这是一个简化示例:

//! Schedules a callable to be executed asynchronously
template<class F> void schedule(F &&f);

int main(void)
{
  bool flag(false);

  // Ignore the fact this is thread unsafe :)
  schedule([&] { flag=true; });

  // Can the compiler assume under strict aliasing that this check
  // for flag being false can be eliminated?
  if(!flag)
  {
    // do something
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

显然代码片段是线程不安全的 - bool标志需要是std :: atomic,然后seq_cst内存排序会强制编译器始终检查if测试的值.这个问题与此无关 - 它是关于初始化一个捕获全部引用lambda是否告诉编译器该标志可能已被别名,因此不能在稍后优化时检查标志值?

我自己的个人猜测是,构建一个[&flag] {...} lambda会暗示标志的潜在混叠,而[&] {...}使用潜在的别名来破坏所有自动初始化的变量听起来太极端反优化所以我猜不到.但是,如果引用捕获lambda不会对clobber进行任何别名,我也不会感到惊讶.

给你C++语言专家!我提前感谢你.

编辑:我知道缺乏线程安全将被视为一个答案,但这不是我要求的.让我进一步减少我的榜样:

int main(void)
{
  bool flag(false);

  // Note that this is not invoked, just constructed.
  auto foo=[&] { flag=true; };

  // Can the compiler assume under strict aliasing that this check
  // for flag being false can be eliminated?
  if(!flag)
  {
    // do something
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在可以检查标志是否为假?

编辑:对于那些将来来到这里的人,我对下面答案的最好理解是"是的,可以省略检查",即构造一个lambda,它通过引用获取局部变量,编译器的优化器不会将其视为可能修改该变量,因此编译器的优化器可以合法地忽略该变量存储的后续重载.感谢大家的回答.

R. *_*des 5

你不能忽视缺乏线程安全性.数据竞争产生未定义的行为,并且此代码具有数据竞争,因此答案为"编译器是否可以在严格别名下假设可以消除对该标志为false的检查?" 是"编译器可以做任何想做的事情."

如果您修复它并使代码线程安全std::atomic<bool>,则问题消失:编译器不能丢弃检查,因为它必须符合原子变量的内存模型要求.

相反,如果schedule调用没有执行与多线程相关的任何操作,则编译器必须保留抽象机器的语义.抽象机程序检查标志的值,而是一个编译器可能能够执行该证明标志将始终有一定的价值(或者总是静态分析false或总是true),并跳过检查.这是在as-if规则下允许的:不可能编写一个能够可靠地区分两种可能性(优化与否)的C++程序.

因此,对于第二个示例,答案是"编译器可以执行任何操作,只要可观察行为与执行检查相同即可."