0
#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;
}

I run code here: https://www.programiz.com/cpp-programming/online-compiler/ output is :

p is 0x5628eb47deb0
0x5628eb47deb0
size is 2
end

if I set ptr to nullptr after delete, it will crash at push_back. But still fine when I access the list.

How is it even possible that I push data to a dangling pointer without crashing it??

Michael
  • 1,313
  • 11
  • 25
  • 2
    undefined behaviour is undefined. Just because it seemingly does something does not mean doing it is correct. – Raildex Sep 26 '21 at 12:17
  • 1
    Dereferencing invalid pointers lead to *undefined behavior*. Sometimes it gives you a crash, sometimes is skins your cat alive, and if you're really unlucky nothing happens at all. You can never know beforehand which alternative it's going to be. – Some programmer dude Sep 26 '21 at 12:17
  • 1
    @Someprogrammerdude Seems that the PC of my cousin's friend once exploded after deferencing a dangling pointer – MatG Sep 26 '21 at 12:19
  • 1
    After you `delete` an object, you are not allowed to access the object. You accessed the object. On my machine, your program crashes. *shrug* That's **undefined behavior** for you. – Eljay Sep 26 '21 at 12:20
  • Does this answer your question? [Dereferencing deleted pointers always result in an Access Violation?](https://stackoverflow.com/questions/2896238/dereferencing-deleted-pointers-always-result-in-an-access-violation) – m7913d Sep 26 '21 at 21:06
  • 1
    @m7913d Yeah, especially this one: the runtime libs don't always hand the memory back to the OS right away :) – Michael Sep 27 '21 at 02:30

2 Answers2

3

When you have a pointer to a class, and call a non-virtual function on it, whatever the address is at the pointer will be considered the this pointer. Even if it is zero. As long as you don't try to access members at that address, you should have no problem printing the this poniter.

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;
    }

When you delete a pointer and don't set its address to null, the previous address value is kept.

Accessing a deleted pointer is undefined behavior. It is not required to crash. It just may be that the random data that you are pointing to has some meaning somewhere else in the program. It may even be your old data. Deleting a pointer tells the system it can reuse that memory, but it may not have had time to reuse it yet, and so the old data could still be visible.

Finally your program crashes when you uncomment your line because that sets ptr = 0, and &(0x0000000->l) is an invalid memory reference.

Gonen I
  • 5,576
  • 1
  • 29
  • 60
-1

Pointer continues to reference to the address after you delete it. You can still use the pointer but there will be trash(mostly) in the address.

#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;
}

Result:

1
1
2
korzck
  • 198
  • 9
  • 1
    don't delete a pointer that's coming from the stack. That's another mistake. Change your example to use new. And there is no need for two pointers, since this complicates the example. Keep your examples simple. – Gonen I Sep 26 '21 at 15:58
  • You can change your example to something like the following: int *p = new int[10000]; p[5000]=7; cout << p[5000] << endl; // 7 delete[] p; cout << p[5000] << endl; // 7 – Gonen I Sep 26 '21 at 16:05
  • Please do not promote/justify the use of undefined behavior. – m7913d Sep 26 '21 at 17:53
  • @m7913d i didn't mean to promote/justify this, i just showed that deleted pointer still has the address and there is nothing undefined. I said it would contain trash. – korzck Sep 26 '21 at 19:28
  • @korzck Please check these questions: https://stackoverflow.com/questions/43508771/use-of-a-deleted-pointer-address and https://stackoverflow.com/questions/441831/calling-delete-on-variable-allocated-on-the-stack Your answer is 2xUB (in C++11)! – m7913d Sep 26 '21 at 20:10
  • @m7913d ofc thats true, but i used other pointer to show that the address is still stored in the pointer(thats actually not forbidden). If you'll try to compile and run smth where you use deleted pointer without other pointer you will get runtime error. – korzck Sep 26 '21 at 20:45
  • What you are showing is that SOME implementation behave like you show, but this should not be relied on in general. After calling `delete ptr`, also `ptr_a` is an invalid pointer. The [C++11 standard](https://timsong-cpp.github.io/cppwp/n3337/basic.stc.dynamic.deallocation#4) states: _a deallocation function [...] rendering invalid all pointers referring to any part of the deallocated storage_. – m7913d Sep 26 '21 at 20:59