-1

I use MS Visual Studio 2010.

I made implementation of a double-linked list.

I wonder why in main function after invoking method Clean, which invoke destructor of an object, after I refer to the object no errors are raised.

Here are some of my double-linked list methods(relative to my question):

/*DoubleLinkedList.cpp */  
         DoubleLinkedList::~DoubleLinkedList(void)
        {
        cout << "Destructor invoked" << endl;
        // as for data nodes memory is allocated in heap we have to release it:
        const Node* const_iterator = m_head.m_next;
        while (const_iterator != &m_tail)
        {
            const_iterator = const_iterator->m_next;
            delete const_iterator->m_prev;
        }
    }

void DoubleLinkedList::Clean(void)
{
    cout << "Clean invoked" << endl;

    this->~DoubleLinkedList(); /* According to C++ 11 standart: Once a destructor is invoked for an object, the object no longer exists*/
}

/* main.cpp */
    int main(int argc, char* argv[])
    {
        DoubleLinkedList list;
        Circle c1, c2(MyPoint(1,1),50), c3(MyPoint(2,2),30);
        list.Front(&c1);
        list.Front(&c2);
        list.Front(&c3);
        list.Show();
        list.Sort();
        list.Show();
        list.Clean();
        list.Show(); /* Recall how Clean method is implemented. As list no longer exist, run-time error is expected here, but flow of executon continues and Show, Push_back preforms fine*/
        list.Push_back(&c1);
        list.Push_back(&c2);
        list.Push_back(&c3);

Question: *As stated in the 11 standart of C++ after destructor is called - object no longer exists*, why I am still able to use the object after it`s destructor was invoked?

ildjarn
  • 62,044
  • 9
  • 127
  • 211
spin_eight
  • 3,925
  • 10
  • 39
  • 61
  • 2
    Referring to an object which no longer exists is *undefined behaviour*. Which means your program might crash, or it might not. C/C++ do not provide safety netting, and are not required to tell you if you make a mistake. – DevSolar Feb 28 '13 at 08:51
  • 2
    See also: http://stackoverflow.com/a/6445794/78845 – johnsyweb Feb 28 '13 at 08:54
  • You've misunderstood it. I think the true meaning is *when the object is no longer existent its destructor should be called*. C++ compiler guarantees that the destructor of every object is automatically called when exiting the scope. – neuront Feb 28 '13 at 08:55
  • @ DevSolar Thank you, your explanation made things clear – spin_eight Feb 28 '13 at 08:55
  • **Note:** `this->~DoubleLinkedList();` calls the destructor. `this->~DoubleLinkedList();` ***does not*** `delete` the object. – johnsyweb Feb 28 '13 at 08:59
  • @Johnsyweb - you mean that object still resides in memory, thanks I think that is good info to point out – spin_eight Feb 28 '13 at 09:05
  • @spin_eight: I mean a destructor is just a member function, which can be called at any time. Destructors are called automatically on `delete`, of course. It is `delete` that frees an object's memory, not the destructor. – johnsyweb Feb 28 '13 at 09:07
  • @Johnsyweb how about an object in stack?? delete is not applicable in this situation, but although object can be released from the main memory/ – spin_eight Feb 28 '13 at 09:09
  • 1
    This is not a duplicate of "Can a local variable's memory be accessed outside its scope?" This is about calling a destructor; not about deleting an object! I vote to re-open so I can write a proper answer and not answer in the comments! – johnsyweb Feb 28 '13 at 09:09
  • 1
    @spin_eight - After calling the destructor, there is no object anymore (just some memory). The fine distinction between deleting the object and destroying the object isn't all that interesting. – Bo Persson Feb 28 '13 at 09:37
  • @Bo Persson so if there is no object anymore, then all info related to that object no longer exist, so no longer exists table of objects methods?? if so why it is possible to call list.show()? – spin_eight Feb 28 '13 at 10:02
  • 2
    @spin_eight It isn't possible, but "Seeming to work" is one possible effect of undefined behavior. Please read [the answer about the hotel room](http://stackoverflow.com/a/6445794/597607), where checking out doesn't make the room go away. This is exactly the same. – Bo Persson Feb 28 '13 at 10:09
  • @Bo Persson thank you for the good source of information, it partly addreses my question, but there is still uncovered info about methods invokage, but I think I shall cope with it by myself. Thank you! – spin_eight Feb 28 '13 at 10:26
  • 1
    @spin_eight: Typically there isn't a per-object function table. There is one table shared by all objects of the same class and a pointer to the specific object is passed as a hidden parameter to the member function. Calling a member function with a destroyed object just passes an invalid `this` pointer. Note this is all an implementation detail but it explains why this can appear to work. – Blastfurnace Feb 28 '13 at 17:42
  • Please read http://c-faq.com/ansi/experiment.html before saying "a runtime error is expected", especially the Roger Miller quote – Jonathan Wakely Feb 28 '13 at 18:32
  • @Blastfurnace oh, now I see what is the case, I just now recalled about a table for class, I wronly applied it to instances thank you for pointing to my mistake. The question has been sorted out and partly with your help, so thank you! – spin_eight Feb 28 '13 at 18:36
  • @spin_eight: The basic idea here is that "deleting" or "destructing" something in C/C++ doesn't mean it's gone from memory, it just means that it's no longer allocated, and the memory might be used for something else at any time. The language doesn't bother zeroing out memory before de-allocating it (for performance reasons), so you might still see the "aftershadow" of what was once there - or you might not, it's undefined. – DevSolar Mar 01 '13 at 05:48

2 Answers2

3

The important thing to consider here is the lifetime of the object. The lifetime of an object must exist within the time that the storage for that object has been allocated. Many objects can exist at a single storage location within the time that storage is allocated, one after the other.

Normally, when an object is destroyed (through going out of scope or calling delete), the objects lifetime is ended and then its memory is deallocated. However, when you call the destructor explicitly, all you do is end the lifetime of your object. The standard has no definition of the object "not existing", but it does have the concept of its lifetime ending.

The lifetime of an object of type T ends when:

  • if T is a class type with a non-trivial destructor (12.4), the destructor call starts, or
  • the storage which the object occupies is reused or released.

Now, in the state after an objects lifetime has ended and before its storage has been deallocated, there are only very specific things you can do. The standard defines things that can be done in this state to both pointers and glvalues. In your case, list is a glvalue, so we'll take a look at the rules for that:

[...] after the lifetime of an object has ended and before the storage which the object occupied is reused or released, any glvalue that refers to the original object may be used but only in limited ways. [...] The program has undefined behavior if:

  • an lvalue-to-rvalue conversion (4.1) is applied to such a glvalue,
  • the glvalue is used to access a non-static data member or call a non-static member function of the object, or
  • the glvalue is implicitly converted (4.10) to a reference to a base class type, or
  • the glvalue is used as the operand of a static_cast (5.2.9) except when the conversion is ultimately to cv char& or cv unsigned char&, or
  • the glvalue is used as the operand of a dynamic_cast (5.2.7) or as the operand of typeid.

The second list item applies here. You have undefined behaviour beacuse you're accessing a non-static member function after the objects lifetime has ended.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • If object no longer exists should all support info associated with it be deleted (I mean virtual table for example), if so why it is still possible to invoke methods of that object or invokage is undefined behaviour? – spin_eight Feb 28 '13 at 10:10
  • 1
    @spin_eight It's undefined behaviour. The standard says nothing about virtual table and such. Anything can happen. – Joseph Mansfield Feb 28 '13 at 10:31
2

Use object AFTER it's destroyed (i.e. destructor's is called) is UB. UB means undefined behaviour. So...

ForEveR
  • 55,233
  • 2
  • 119
  • 133