2012-08-25 41 views
0

鉴于这种一小段代码:断言这两个指针指向NULL不发生后删除()

#include <iostream> 
#include <assert.h> 
using namespace std; 


struct Foo 
{ 
    // something 
}; 


int main() 
{ 

    Foo *p1 = new Foo; 
    Foo * p2 = p1; 
    assert(NULL != p1); 
    delete p1; 
    p1 = NULL; 

    assert(NULL != p2); 
    delete p2; 

    cout << "everything is cool!" << endl; 

    return 0; 
} 

当我删除p1,第二断言(assert(NULL != p2);)没有失败,为什么?

输出:everything is cool!

那么为什么p2断言不会失败?

+1

因为p2仍然设置为p1所具有的地址。在更改之后,它不会获得p1的值。 – drescherjm

回答

2
  1. 特别注意星星。

    int i; 
    
    int *p1 = &i; 
    assert(p1 != NULL); 
    
    int *p2 = p1; 
    assert(p2 != NULL); 
    
    *p1 = 10; 
    assert(i == 10); 
    assert(*p2 == 10); 
    
    p1 = NULL; // does not affect the object p1 was pointing at 
    
    assert(i == 10); 
    assert(*p2 == 10); 
    assert(p2 != NULL); // (which we already know, if the previous assert didn't crash) 
    
  2. 你是对的怀疑,一切都不是很酷。该程序在同一个对象上调用delete操作符两次(“double free”错误),这往往会破坏堆。如果程序继续,您会在某个时间点看到未定义的行为。具有未定义的行为相当于打破了编写计算机程序的观点。如果您想立即明确地看到类似这样的错误,请在valgrind的memcheck或equivalent下运行。

4

当我删除p1时,第二个断言(assert(NULL!= p2);)不是 失败,为什么?

删除p1或分配给它的p2本身没有影响。删除p1后,p2仍指向该地址,即指向已停用的对象。它变成了一个所谓的悬挂指针。当然,访问它或删除它(你正在做的)是未定义的行为。

+0

“非法”应该是“未定义的行为” – tenfour

+0

@tenfour我只是厌倦了“未定义的行为”,认为我会尝试一些不同的行为。 – cnicutar

0

delete p;不影响p。它破坏了p所指向的对象并释放其内存。 p仍然有它以前的价值。

1

在C++中,最大和最容易混淆的词之一是术语“删除指针”。这无疑源于这样一个事实:delete表达需要指针作为它的参数:

T * p = new T; // #1 
delete p;  // #2 

然而,到底发生了什么的是线#1创建一个新的,动态的,无名对象。再想一想:有没有变量,其值是在#1行中创建的对象。这个东西实在遥不可及,因为它确实不在任何范围内。我们所有的是指针

要结束动态变量的生命周期,我们必须使用delete表达式。但既然我们已经知道,我们永远只能真的有指针的对象,而不是对象本身*,表达CON ­ VENI ­耳鼻喉科­立法院接受指针到我们删除的对象。

所以我们应该说,在第2行“我们通过给它指向delete表达式”(即&*p == p)来删除对象*p

指针本身完全不受delete调用的影响。

*)是的,我们也可以有一个参考变量,像T & r = *new T;,但是这将是疯狂的。