6

当同一段代码在完全禁用优化的情况下编译g++ -O0g++ -O3

例如,编译器可以

这两个优化使代码执行得更快,而不会影响原始源代码的完整性。任何在没有这些优化的情况下运行的代码都将在启用它们的情况下运行。

但是,编译器优化也会影响代码逻辑。以下是我知道的两个例子:

我很惊讶,也很幸运,了解到这些,因为在错误的情况下它们可能会成为巨大的潜在陷阱。

所以我想知道,是否还有其他情况下c++编译器优化会影响代码逻辑?我专门在 g++ 编译器下寻找有关 c++11 的信息(没有任何未定义的行为),但欢迎使用其他编译器的提示。

4

2 回答 2

8

“好像”规则:

只要从程序的可观察行为中可以确定,只要结果好像已经遵守了要求,就可以自由地忽略本国际标准的任何要求。例如,如果一个实际的实现可以推断出它的值没有被使用并且没有产生影响程序可观察行为的副作用,那么它就不需要评估表达式的一部分。

但是,该标准提到了一种允许的优化,它打破了“as-if”规则:

当满足某些条件时,允许实现省略类对象的复制/移动构造,即使对象的复制/移动构造函数和/或析构函数具有副作用。在这种情况下,实现将省略的复制/移动操作的源和目标简单地视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象本应被删除的较晚时间。在没有优化的情况下销毁。123 这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合起来消除多个副本):

— 在具有类返回类型的函数的 return 语句中,当表达式是具有与函数返回类型相同的 cvunqualified 类型的非易失性自动对象(函数或 catch 子句参数除外)的名称时,可以通过将自动对象直接构造到函数的返回值中来省略复制/移动操作

— 在 throw 表达式中,当操作数是非易失性自动对象(函数或 catch 子句参数除外)的名称时,其范围不超出最里面的封闭 try 块的末尾(如果有一)、从操作数到异常对象(15.1)的复制/移动操作可以通过将自动对象直接构造到异常对象中来省略

— 当尚未绑定到引用 (12.2) 的临时类对象将被复制/移动到具有相同 cv-unqualified 类型的类对象时,可以通过将临时对象直接构造到省略复制/移动的目标

— 当异常处理程序的异常声明(第 15 条)声明与异常对象(15.1)具有相同类型的对象(cv 限定除外)时,可以通过处理异常声明来省略复制/移动操作作为异常对象的别名,如果程序的含义将保持不变,除了为异常声明声明的对象执行构造函数和析构函数。

于 2012-10-18T04:22:57.187 回答
1

“未指定行为”是实现可以自由选择任何可能行为的行为。在这种情况下,优化器可能会影响所做的选择。

一个简单的例子是计算函数参数的顺序。未优化的构建可以使用从左到右或从右到左,而优化的构建可以以“混合”顺序评估参数。一个很好的理由是在参数中最大化公共子表达式优化的机会。

如果这些参数中的任何一个具有明显的副作用,则代码逻辑将被更改,但这是否是错误因情况而异。

于 2012-10-18T12:03:16.603 回答