2

我在重现和查找错误原因时遇到了很大的问题。发生似乎完全是随机的,所以我怀疑某处有一个未初始化的变量。但后来我发现了这段代码:

CMyClass obj; // A
obj.DoStuff();

if ( somebool )
{
    CMyClass obj; // B
    obj.DoStuff();
}

obj.DoOtherStuff();

似乎 DoOtherStuff() 要么在“B”上完成,要么 B.DoStuff() 有时实际上在 A 上工作 - 即我 DoStuff() 实际上是在第一个 obj 上调用的。

这会发生吗?我认为我没有收到编译器警告(我现在已经修复了代码,希望它可能会有所帮助)。这段实际代码似乎可能是我要查找的错误所在,但当然可能还有其他我尚未发现的原因。

4

6 回答 6

5

编写的代码应该可以工作。第一次调用DoStuff()和最后一次调用DoOtherStuff()只能发送到A

DoStuff()块内的调用if(somebool) { }只能发送到B.

标准

3.3.2 局部范围

  1. 在块 (6.3) 中声明的名称是该块的本地名称。它的潜在范围从其声明点 (3.3.1) 开始,并在其声明区域的末尾结束。

和:

3.3.7 名称隐藏

  1. 可以通过在嵌套声明区域或派生类 (10.2) 中显式声明相同名称来隐藏名称。

话虽如此,也许这不是该代码作者的意图。如果变量具有相同的名称,则可能意图是只有该变量的一个实例,而B在循环内创建的实例是错误的。您是否通过逻辑来查看第二个实例是否有意义?

于 2009-05-16T17:37:02.057 回答
3

除非obj.DoStuff()对某个全局对象进行更改,否则正如 Valentin 指出的那样,它应该全部包含在 if 语句的范围内

于 2009-05-16T17:38:35.203 回答
2

与全局变量同名的局部变量隐藏了该块内的全局变量。但是,全局范围运算符 (::) 可用于告诉编译器您的意思是全局版本

CMyClass obj; // A
obj.DoStuff();
if ( somebool )
{ 
 CMyClass obj; // B  
 obj.DoStuff();  //does on B
 ::obj.DoStuff(); //does on A
}
obj.DoOtherStuff(); //this will call A because B is destroyed

所以局部变量 B 在超出范围时被销毁。使用与全局变量同名的局部变量通常会带来麻烦,因此请尽可能避免使用。

于 2009-05-16T17:38:38.823 回答
2

如果您使用 GCC,您可以(并且 - 在我看来 - 应该)使用 -Wshadow,它会在示例中的情况下发出警告,这通常会导致非常微妙的错误。

但是,就像许多其他人已经说过的那样,您粘贴的代码是正确的,符合您的预期,并且不是未定义的行为。

于 2009-05-16T18:31:59.007 回答
1

不,这不可能发生。

编译器保证 B 对象在退出 if 作用域时被正确销毁,并且在它还活着的时候它作用于自己的地址空间。

错误在其他地方。

于 2009-05-16T17:35:25.570 回答
0

您的代码可能在语法上是正确的,但这些方法的作用是什么?例如,堆栈溢出可能会导致您正在观察的怪异行为。

于 2009-05-16T18:52:38.020 回答