Exc*_*ius 7 c++ optimization visual-c++ visual-studio-2012
首先:我知道大多数优化错误是由于编程错误或依赖于可能根据优化设置(浮点值,多线程问题......)而改变的事实.
然而,我经历了一个非常难以找到的错误,并且有些不确定是否有任何方法可以防止这些错误发生而不关闭优化.我错过了什么吗?这真的是一个优化器错误吗?这是一个简化的例子:
struct Data {
int a;
int b;
double c;
};
struct Test {
void optimizeMe();
Data m_data;
};
void Test::optimizeMe() {
Data * pData; // Note that this pointer is not initialized!
bool first = true;
for (int i = 0; i < 3; ++i) {
if (first) {
first = false;
pData = &m_data;
pData->a = i * 10;
pData->b = i * pData->a;
pData->c = pData->b / 2;
} else {
pData->a = ++i;
} // end if
} // end for
};
int main(int argc, char *argv[]) {
Test test;
test.optimizeMe();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
真正的程序当然还有很多工作要做.但这一切都归结为这样一个事实,即不使用直接访问m_data,而是使用(先前已经单元化的)指针.一旦我向if (first)-part 添加了足够的语句,优化器似乎就会将代码更改为以下内容:
if (first) {
first = false;
// pData-assignment has been removed!
m_data.a = i * 10;
m_data.b = i * m_data.a;
m_data.c = m_data.b / m_data.a;
} else {
pData->a = ++i; // This will crash - pData is not set yet.
} // end if
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它通过直接写入成员结构来替换不必要的指针取消引用.但是它不会在else-branch中执行此操作.它还删除了pData-assignment.由于指针现在仍然是单元化的,程序将在-branch中崩溃else.
当然,这里可以改进各种各样的东西,所以你可能会把它归咎于程序员:
m_data直接使用.else如果从未分配指针,优化器将知道-branch将失败.至少它似乎解决了我的测试环境中的问题.pData有&m_data,然后也可能是一个参考,而不是一个指针(好措施).这是有道理的,因为pdata将需要在所有的情况下,所以没有理由这样做内循环.至少可以说,代码显然很臭,而且我并没有试图"责怪"优化器这样做.但我问:我做错了什么?该程序可能很丑,但它是有效的代码......
我应该补充一点,我正在使用VS2012和C++/CLI以及v110_xp-Toolset.优化设置为/ O2.还请注意,如果你真的想重现这个问题(虽然这不是问题的真正意义),你需要解决程序的复杂性.这是一个非常简化的示例,优化器有时不会删除指针赋值.躲在&m_data功能背后似乎"有所帮助".
编辑:
问:我如何知道编译器正在将其优化为类似提供的示例?
答:我不太擅长阅读汇编程序,但是我已经查看了它并且做了3次观察,这让我相信它的行为方式如下:
pData和内容m_data,它会清楚地显示if-branch 中的所有赋值都会产生影响m_data并m_data接收正确的值.指针本身仍然指向它从一开始就具有的相同的未初始化值.因此,我必须假设它实际上并没有使用指针来进行赋值.问:它是否必须对i做任何事情(循环展开)?
答:不,实际程序实际上使用do {...} while()来循环SQL SELECT结果集,因此迭代计数完全是运行时特定的,并且不能由编译器预先确定.
这对我来说肯定是个错误.优化器可以消除不必要的重定向,但它不应该消除分配pData.
当然,您可以通过pData在循环之前分配来解决问题(至少在这个简单的示例中).我认为实际代码中的问题并不容易解决.