2013-02-27 181 views
-4

如果我们在下面注释掉强调的行,我们会在控制台中获得777。 否则我们会得到一些垃圾,如(-534532345)。 我的环境是Microsoft Visual Studio 2012 Pro。跟踪对象和引用

class C 
{ 
public: 
    C() { x = 777; } 
    void ou() {cout << x;} 
protected: 
    int x; 
}; 

class A 
{ 
public: 
    A(C & rrc) : rc(rrc) {}; 
    void koo() {rc.ou();} 
protected: 
    C & rc; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    C c; 
    C * pc = new C; 
    A a(*pc); 
    delete pc; // <<<< this line 
    a.koo(); 

    return 0; 
} 

任何人都可以帮我弄清楚为什么我看到这种行为?

+2

为什么这会构成语言中的“漏洞”? C++ *不是一种安全的语言*,并且不会像这样公布。 – 2013-02-27 23:10:33

回答

7

在您呼叫a.koo()的位置,您已删除其rc引用所引用的基础对象。这当然是UB。接下来发生的情况可能会在给定的编译平台上具有一致的行为,甚至可能输出777(实际上,可能会输出777,因为底层对象最近被删除)。在你的情况下,似乎以前分配给_tmain()的对象的内存已被重新分配给覆盖它的其他内容,否则你使用的调试版本的内存分配器明确地覆盖了已删除/释放一些固定值的内存,通常为非零值,而不是全部值,但是其他可识别的值如0xAAAAAAAA或0xDEADDEAD。由于-534532345是0xE023AF07(或0xFFFFFFFFE023AF07),我猜它是前者(内存已被分配给其他覆盖它的其他内容)。既然在你的例子中对a.koo()的调用立刻跟在delete pc之后,我觉得它很快就被覆盖了,但从技术上来说任何事情都是可能的,因为它是UB。

+0

现在找不到源代码,但MSVC中的iirc'delete'在调试版本中故意用垃圾值覆盖内存,以使这些错误更加明显。 – 2013-02-27 23:24:40

+0

@StephenLin - 有趣。看起来好像会用容易识别为未分配内存的签名的nongarbage值覆盖它,例如0xAAAAAAAA或0xDEADDEAD。当然,我的代码是完美的,所以我从来没有看到这样的错误;)但是我可以发誓,我已经看到了某些平台上可识别的值,用于调试构建。 – phonetagger 2013-02-27 23:27:32

+0

嗯,本身可能不是垃圾 - 不幸的是,仍然找不到链接。 – 2013-02-27 23:31:42

4

该删除使您留下一个悬挂的引用,您遵循,导致未定义的行为。这不是C++或MS VS中的漏洞。该语言允许许多非法行为不受检查,并且让程序员不要调用UB。

4

该代码有未定义的行为。您持有不再存在的对象的引用。所以,rc.ou()行为是未定义的。

1

如果你删除了pc,那么A :: rc将指向垃圾位置和rc.ou();也会输出垃圾。这是正常现象,它会做到这一点无论编译器使用的是

顺便说一下99 [0.99]你认为你已经找到了一个编译器错误%的时间,这真的是你的错误