C++ 优化器错误还是编程错误?
首先:我知道大多数优化bug都是由于编程错误或依赖于一些事实造成的,这些事实可能会根据优化设置(浮点值、多线程问题等)而改变 然而,我遇到了一个很难找到的bug,我有点不确定是否有任何方法可以在不关闭优化的情况下防止此类错误的发生。我错过什么了吗?这真的是一个优化器错误吗?下面是一个简化的示例:C++ 优化器错误还是编程错误?,c++,visual-c++,optimization,visual-studio-2012,C++,Visual C++,Optimization,Visual Studio 2012,首先:我知道大多数优化bug都是由于编程错误或依赖于一些事实造成的,这些事实可能会根据优化设置(浮点值、多线程问题等)而改变 然而,我遇到了一个很难找到的bug,我有点不确定是否有任何方法可以在不关闭优化的情况下防止此类错误的发生。我错过什么了吗?这真的是一个优化器错误吗?下面是一个简化的示例: struct Data { int a; int b; double c; }; struct Test { void optimizeMe(); Data m_da
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;
}
如您所见,它将不必要的指针取消引用替换为直接写入成员结构。但是,它在else
分支中不执行此操作。它还会删除pData
-分配。由于指针现在仍然是单元化的,程序将在else
-分支中崩溃
当然,这里有很多可以改进的地方,因此您可能会将其归咎于程序员:
- 忘记指针,做优化器做的事情-直接使用
m_数据
- 将pData初始化为nullptr—这样优化器就知道,如果从未分配指针,
—分支将失败。至少在我的测试环境中,它似乎解决了这个问题李>else
- 将指针分配移动到循环前面(使用
有效地初始化&m_data
,然后它也可以作为参考而不是指针(为了更好地测量)。这是有意义的,因为在所有情况下都需要pData,因此没有理由在循环内部这样做pData
&m_数据
隐藏在函数后面似乎“有帮助”
编辑:
问:我如何知道编译器正在将其优化为类似于所提供的示例
答:我不太擅长阅读汇编程序,但是我已经看过了,并且做了3个观察,这让我相信它的行为是这样的:
pData
的内容和m_data
的内容,它清楚地显示If
-分支中的所有赋值对m_data
有影响,m_data
接收到正确的值。指针本身仍然指向它从因此,我必须假设它实际上根本没有使用指针来进行赋值答:不,实际的程序实际上使用do{…}while()循环SQL SELECT resultset,使迭代计数完全特定于运行时,并且不能由编译器预先确定。在我看来,这确实是一个错误。优化器可以消除不必要的重定向,但不应消除对
pData的赋值
当然,您可以通过在循环之前分配给pData
来解决这个问题(至少在这个简单的示例中)。我认为实际代码中的问题并不容易解决。我也投票支持优化器错误,如果它在本例中确实是可复制的。要否决优化器,您可以尝试将pData
声明为volatile将其减少为一个。@djechlin:受优化影响的错误可能很难减少到很小代码示例。问题明确说明这已经是一个简化的示例。您是否查看了程序集,或者您只是假设优化器删除了pData
分配?是的……您是否验证了这一点?或者您只是猜测?Microsoft state将使用最高警告级别来避免微妙的困难要找到bug,我相信这就是其中之一,init pData to nullptr,问题很可能会消失。实际上,在实际代码中,删除指针作为一个整体是解决方案。代码已经超过15年了,像这样的大多数bug都很容易解决,因为代码只需要一些简单的重构。找到bug是一个完全困难的过程不同的故事。因为我现在相当确定这是一个编译器错误,所以我会接受这个答案。一旦我向microsoft提交了一个错误报告,我会添加这个问题的链接,这样就会有一个真正的可复制的例子。我想这更像是一个C++/CLI问题,普通的编译器并没有出现问题。
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