As the delete operator deallocates memory, why do I need a destructor?

こ雲淡風輕ζ 提交于 2020-05-14 18:18:05

问题


From c++ FAQ: http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.9

Remember: delete p does two things: it calls the destructor and it deallocates the memory.

If delete deallocates the memory, then what's the need of the destructor here?


回答1:


You need to call the destructor in case there are other things that need to be done other than just de-allocating memory.

Other than very simple classes, there usually are.

Things like closing file handles or shutting down database connections, deleting other objects that are pointed to by members data within your object, and so forth.

A classic example is the implementation of a stack:

class myStack {
    private:
        int *stackData;
        int topOfStack;

    public:
        void myStack () {
            topOfStack = 0;
            stackData = new int[100];
        }

        void ~myStack () {
            delete [] stackData;
        }

        // Other stuff here like pop(), push() and so on.
}

Now think of what would happen if the destructor was not called every time one of your stacks got deleted. There is no automatic garbage collection in C++ in this case so the stackData memory would leak and you'd eventually run out.


This requiring of a destructor to delete all its resources moves down the tree towards the basic types. For example, you may have a database connection pool with an array of database connections. The destructor for that would delete each individual database connection.

A single database connection may allocate a lot of stuff, such as data buffers, caches, compiled SQL queries and so on. So a destructor for the database connection would also have to delete all those things.

In other words, you have something like:

+-------------------------------------+
| DB connection pool                  |
|                                     |
| +-------------------------+---+---+ |
| | Array of DB connections |   |   | |
| +-------------------------+---+---+ |
|                             |   |   |
+-----------------------------|---|---+
                              |   |   +---------+
                              |   +-> | DB Conn |
             +---------+      |       +---------+
             | DB Conn | <----+         /  |  \
             +---------+         buffers   |   queries
               /  |  \                  caches
        buffers   |   queries
               caches

Freeing the memory for the DB connection pool would not affect the existence of the individual DB connection or the other objects pointed to by them.

That's why I mentioned that only simple classes can get away without a destructor, and those are the classes that tend to show up at the bottom of that tree above.

A class like:

class intWrapper {
    private:
        int value;
    public:
        intWrapper () { value = 0; }
        ~intWrapper() {}
        void setValue (int newval) { value = newval; }
        int getValue (void) { return value; }
}

has no real need for a destructor since the memory deallocation is all you need to do.


The bottom line is that new and delete are opposite ends of the same pole. Calling new first allocates the memory then calls the relevant constructor code to get your object in a workable state.

Then, when you're done, delete calls the destructor to "tear down" your object the reclaims the memory allocated for that object.




回答2:


If delete deallocates the memory, then what's the need of the destructor here?

The point of the destructor is to execute any logic required to clean up after your object, for example:

  • calling delete on other objects owned by the object being destroyed
  • properly releasing other resources like database connections; file handles and the like



回答3:


Suppose you have a class that dynamically allocates memory:

class something {
public:
    something() {
        p = new int;
    }

    ~something() {
        delete p;
    }

    int *p;
};

Now let's dynamically allocate a something object:

something *s = new something();

delete s;

Now, if the delete didn't call the destructor, then s->p would never be freed. So delete has to both call the destructor and then deallocate the memory.




回答4:


The destructor is in charge of freeing resources other than the object's allocated memory. For instance, if the object has a file handle open, the destructor could call fclose on it.




回答5:


It deallocates the memory taken up by that object. However, anything that has been allocated by the object (and owned by that object) needs to be taken care of in the destructor.

Also, in general ... FAQs ... usually not wrong.




回答6:


if you declare a class normal (not pointer), it automatically calls constructor and call destructor automatically when the program closes. If you declare as pointer, it call the constructor when initializes using new and does not call destructor automatically until you call delete that pointer using delete




回答7:


The destructor is there to clean up the changes that the object constructor and member functions might have done to the program state. That can be anything - remove the object from some global list, close an opened file, free allocated memory, close a database connection, etc.




回答8:


The destructor would not have been a mandatory feature. The languages like, C, Java, C# don't have destructors. C++ also can live without it.

Destructor is a special facility provided by C++ (same as Constructor). It's called when an object is "destroyed".

Destroy means, the object scope is officially finished and any reference to that object will be illegal. For example:

A* foo ()
{
  static A obj;  // 'A' is some class
  A *p = &obj;
  return p;
}

In above code, obj is a static data created of type A; foo() returns a reference to that obj which is ok, because obj.~A() is not yet called. Suppose obj is non-static. The code will compile, however, A* returned by foo() is now pointing to a memory location which is no more an A object. Means -> the operation is bad/illegal.

Now, you should be able to distinguish between deallocation of the memory and the destruction of the object. Both are tightly coupled, but there is a thin line.

Also remember that destructor can be called at multiple places:

int bar ()
{
  A obj;
  ...
  return 0; // obj.~A() called here
  ...
  return 1; // obj.~A() called here
  ...
  return 2; // obj.~A() called here
}

In above example, obj.~A() will be called only once, but it can be called from any of the places shown.

During the destruction, you may want to do some useful stuff. Suppose class A calculates some result, when the object destroys; it should print the result of calculation. It can be done in C style way (putting some function at every return statement). But ~A() is a readily available one-stop facility.




回答9:


In addition to answers focused on the objects allocated on the heap (with new; which are deallocated only with delete)...Don't forget that if you place the object on the stack (so, without using new), its destructor will be called automatically and it will be removed from the stack (without calling delete) when it goes out of scope. So you have one function that is guaranteed to be executed when object goes out of the scope and that is perfect place to perform cleanup of all other resources allocated by the object (various handles, sockets...and objects created on the heap by this object - if they must not outlive this one). This is used in the RAII idiom.



来源:https://stackoverflow.com/questions/9125271/as-the-delete-operator-deallocates-memory-why-do-i-need-a-destructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!