C++ 在delete()之后不会断言两个指针都指向NULL

C++ 在delete()之后不会断言两个指针都指向NULL,c++,struct,assert,C++,Struct,Assert,给出这段代码: #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

给出这段代码:

#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;
}
#包括
#包括
使用名称空间std;
结构Foo
{
//某物
};
int main()
{
Foo*p1=新的Foo;
Foo*p2=p1;
断言(NULL!=p1);
删除p1;
p1=零;
断言(NULL!=p2);
删除p2;
库特
当我删除p1时,第二个断言(assert(NULL!=p2);)不是
失败了,为什么


删除
p1
或分配给它对
p2
本身没有影响。删除
p1
后,
p2
仍然指向该地址,即指向一个不存在的对象。它成为所谓的悬挂指针。当然,访问或删除它(您正在执行的操作)“未定义的行为”。

<代码>代码>删除p;< /COD>不影响<代码> P<代码>。它破坏了代码> P>代码>指向的对象并释放其内存。<代码> P<代码>仍然具有它以前的值。

< P> C++中初学者误称最大的和最令人困惑的一个术语是“删除指针”。。这无疑源于以下事实:
delete
表达式将指针作为其参数:

T * p = new T;  // #1
delete p;       // #2
然而,真正发生的是第1行创建了一个新的、动态的、未命名的对象。请再想想:没有变量的值是第1行中创建的对象。该对象确实是遥不可及的,因为它确实不在任何范围内。我们所拥有的只是一个指向它的指针

为了结束动态变量的生命周期,我们必须使用
delete
表达式。但是,因为我们已经知道,我们只能真正拥有一个指向对象的指针,而不是对象本身*,因此表达式可以方便地接受指向我们正在删除的对象的指针

因此,实际上我们应该说,在第2行中,“我们正在删除对象
*p
,方法是给它一个指向
delete
表达式的指针”(即
&*p==p

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

*)是的,我们也可以有一个引用变量,比如
T&r=*newt;
,但那太疯狂了

  • 尤其是看星星

    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)
    
  • 你怀疑一切都不酷是对的。程序在同一个对象上调用delete操作符两次(“双重自由”错误),这可能会损坏堆。如果程序继续运行,您将在某个点上看到未定义的行为。如果有未定义的行为,则会破坏编写计算机程序的意义。如果您希望立即明确地看到类似这样的错误,请在valgrind的memcheck或下运行它


  • 因为p2仍然被设置为p1拥有的任何地址。更改后,它不会获得p1的值。“非法”应该是“未定义的行为”@tenfour我只是厌倦了“未定义的行为”,我想尝试一些不同的方法。