是否复制了编译器优化,我可以避免它吗?

时间:2016-01-06 22:08:14

标签: c++ visual-studio

我不喜欢指针,并且通常尝试使用refs编写尽可能多的代码。

我写了一个非常简陋的垂直布局"一个小型Win32应用程序的系统。大多数Layout方法如下所示:

void Control::DoLayout(int availableWidth, int &consumedYAmt)
{
  textYPosition = consumedYAmt;
  consumedYAmt += measureText(font, availableWidth);
}

他们像这样循环:

int innerYValue = 0;
foreach(control in controls) {
  control->DoLayout(availableWidth, innerYValue);
}
int heightOfControl = innerYValue;

它没有在这里绘制内容,只是计算这个控件需要多少空间(通常它也会添加填充等)。这对我很有用.......在 debug 模式下。

我发现在发布模式下,我可以突然看到有形的,可记录的问题,当我循环控制并调用DoLayout()时,consumedYAmt变量实际上保持在0外循环。最烦人的部分是,如果我放入断点并逐行遍历代码,这会停止发生,部分内容会由内部正确更新"添加"方法

我有点想过这是否会是一些编译器优化,他们认为我只是将 ref 标志添加到整数中作为优化内存的方法;或者,如果有任何可能性,它实际上的工作方式与它看起来不同。

我会给出一个可重复的最小例子,但是我用一个小命令行应用程序无法做到这一点。我感觉如果这是一个优化,它只能用于更大的代码块和间接。

编辑:再次抱歉信息普遍较低,但我现在得到提示,这可能是某种链接器问题。我在伪代码中跳过了继承模型的一部分:调用类实际上调用" Layout()",这是类的根定义上的非虚函数。此函数执行一些与实现无关的逻辑,然后使用相同的参数调用DoLayout()。但是,我现在注意到,如果我尝试向Layout()添加断点,Visual Studio声称"断点不会被命中。没有调试器的目标代码类型的可执行代码与该行相关联。"我能够将断点添加到某些其他行,但我开始注意到奇怪的步进逻辑,它拒绝进入某些功能,如Layout。已经尝试完全清除构建文件夹并重建。我必须继续寻找,因为我不得不承认这不是很多。

另外,随机添加:"控制" list是包含shared_ptr对象的向量。我以前没有怀疑过循环机制,但现在我看得更近了。

2 个答案:

答案 0 :(得分:1)

consumedYAmt变量实际上保持为0”

您描述的行为对于特定优化而言是典型的,这种优化更多地归因于CPU而不是编译器。我怀疑你是从另一个线程中记录consumedYAmt。对consumedYAmt的更新根本不会转到其他线程。

这对CPU来说是合法的,因为C ++编译器没有放入内存栅栏。并且CPU编译器没有放入栅栏,因为该变量不是原子的。

在没有线程的小程序中,这根本不会显示,也不会在调试模式下显示。

答案 1 :(得分:0)

由OP撰写

好吧,最终想出了这个。问题很简单,因为Release模式的调试器似乎以不一致的方式运行,因此将其固定下来变得困难。当我改变策略以在很多地方添加Logging语句时,我发现我的Control类有一个" mShowing"在其构造函数中未初始化的变量。在调试模式下,它显然保留了未初始化的内存,我猜这个内存是真的" true" - 但是在发布模式下,我最好的分析是内存保护使其默认为" false",因为事实证明它大部分时间都跳过了DoLayout方法的主体。

由于整个过程,响应者的信息很少(如果我发布更长的例子,当然可能会更容易),而只是简单地提出了每个提到未初始化变量的评论。