使用 -O3 优化依赖此 C++ 函数调用的求值顺序是否安全?

问题描述 投票:0回答:1

我遇到了一些 C++20 代码的问题,这些代码在发行版(-O3、clang 15)中编译时崩溃,并且由于在最终可执行文件上应用了许多混淆技术,因此调试起来非常棘手很难看到实际执行的 x86_64 ASM。

尽管如此,我还是设法将崩溃范围缩小到以下伪代码......

for (std::wstring& data : datas)
{
    auto id = std::format(L"foo_{0}", data);

    do_something(id, std::move(data));
}

...其中

do_something
的签名如下所示:

void do_something(const std::wstring&, std::wstring);

基本上,我认为在设置调用时应该已经调用第二个参数的

std::wstring
的移动构造函数。

现在,这段代码在 -O2 下工作得很好,但是当启用 -O3 时它就崩溃了,我有一种预感。

通读C++标准,我们可以看到以下内容...

任何表达式的任何部分的求值顺序,包括函数参数的求值顺序均未指定(下面列出了一些例外)。编译器可以按任意顺序计算操作数和其他子表达式,并且在再次计算相同表达式时可以选择其他顺序。

我还了解到,C++ 编译器可以在没有副作用的情况下自由优化局部变量(但尚未在标准中找到此特定规则)。

是否因为上面代码中

std::format
本身没有副作用,编译器在使用-O3时将其“内联”到函数调用中?当它发生时,评估的顺序是未定义的,因此移动实际上发生在调用 std::format 之前

基本上我要问的是:C++ 标准允许我描述的优化吗?

c++ optimization standards
1个回答
0
投票
是否是因为上面代码中的 std::format 本身没有副作用,所以编译器在使用 -O3 时将其“内联”到函数调用中?

不。或者,如果确实如此,它将保持指令顺序,以便在第二个参数的 (

std::format

) 移动构造函数之前调用 
std::wstring
。否则,行为良好的代码将变成未定义的行为,而这不是编译器允许做的事情。

© www.soinside.com 2019 - 2024. All rights reserved.