【问题标题】:Why access deleted pointer won't crash the program?为什么访问已删除的指针不会使程序崩溃?
【发布时间】:2021-09-26 12:13:09
【问题描述】:
#include <iostream>
#include<list>

using namespace std;
template <class T>
class Ptr {
public:
    Ptr() {
        a = nullptr;
        l.push_back(0);
    }

std::list<int> l;
void print_this() {
    cout<<this<<endl;
}

protected:
    int *a;
};

int main()
{
    Ptr<int> *ptr = new Ptr<int>();
    delete ptr;
    //ptr = nullptr; //if uncomment this line will crash
    auto p = &(ptr->l);  
    cout<<"p is "<<p<<endl;
    ptr->print_this();
    ptr->l.push_back(1);
    cout<<"size is "<<ptr->l.size()<<endl;
    cout<<"end";
    return 0;
}

我在这里运行代码:https://www.programiz.com/cpp-programming/online-compiler/ 输出是:

p is 0x5628eb47deb0
0x5628eb47deb0
size is 2
end

如果我在删除后将 ptr 设置为 nullptr,它将在 push_back 处崩溃。但是当我访问列表时仍然可以。

我怎么可能将数据推送到一个悬空指针而不使其崩溃??

【问题讨论】:

  • 未定义的行为是未定义的。仅仅因为它看似做了某事并不意味着它是正确的。
  • 取消引用无效指针会导致未定义的行为。有时它会让你崩溃,有时会让你的猫活着,如果你真的很不幸,什么都不会发生。您永远无法事先知道它会是哪种替代方案。
  • @Someprogrammerdude 好像我表哥朋友的电脑曾经在拒绝悬空指针后爆炸
  • delete 一个对象后,您将无法访问该对象。您访问了该对象。在我的机器上,你的程序崩溃了。 耸耸肩这对你来说是未定义的行为
  • @m7913d 是的,尤其是这个:运行时库并不总是立即将内存交还给操作系统 :)

标签: c++ c++11


【解决方案1】:

当你有一个指向一个类的指针,并在它上面调用一个非虚函数时,无论指针处的地址是什么,都会被认为是 this 指针。即使它是零。只要您不尝试访问该地址的成员,打印此指针应该没有问题。

struct A {
    void printThis() {
        printf("%d\n", this);
    }
};

    int _tmain(int argc, _TCHAR* argv[])
    {
        A * a = (A*) 777;
        a->printThis(); // will print 777
    
        a = NULL;
        a->printThis(); // will print 0
    
        return 0;
    }

当你删除一个指针并且不将它的地址设置为空时,之前的地址值会被保留。

访问已删除的指针是未定义的行为。它不需要崩溃。可能只是您指向的随机数据在程序的其他地方具有某种意义。它甚至可能是您的旧数据。删除指针告诉系统它可以重用该内存,但它可能还没有时间重用它,因此旧数据仍然可见。

最后,当您取消注释您的行时,您的程序会崩溃,因为它设置 ptr = 0,并且 &(0x0000000->l) 是无效的内存引用。

【讨论】:

    【解决方案2】:

    删除后指针继续指向地址。您仍然可以使用指针,但地址中会有垃圾(大部分)。

    #include <iostream>
    using namespace std;
    int main()
    {
        int a = 1;
        int *ptr_a = &a;
        int *ptr = &a;
        cout << *ptr_a << endl;
        cout << *ptr << endl;
        delete ptr;
        *ptr_a = 2;
        cout << *ptr << endl;
    }
    

    结果:

    1
    1
    2
    

    【讨论】:

    • 不要删除来自堆栈的指针。那是另一个错误。更改您的示例以使用新的。并且不需要两个指针,因为这会使示例复杂化。保持示例简单。
    • 您可以将示例更改为以下内容: int *p = new int[10000]; p[5000]=7; cout
    • 请不要宣传/证明使用未定义的行为。
    • @m7913d 我并不是要宣传/证明这一点,我只是表明删除的指针仍然具有地址并且没有任何未定义的内容。我说它会包含垃圾。
    • @korzck 请检查这些问题:stackoverflow.com/questions/43508771/…stackoverflow.com/questions/441831/… 你的答案是 2xUB(在 C++11 中)!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-04
    • 2018-05-22
    • 1970-01-01
    • 2014-07-16
    • 1970-01-01
    • 2017-05-02
    • 1970-01-01
    相关资源
    最近更新 更多