Thread: destructors and parameters + pointers to classes questions.

  1. #1
    Registered User
    Join Date
    Dec 2007
    Location
    Denmark
    Posts
    14

    Question destructors and parameters + pointers to classes questions.

    2 questions.

    Why doesn't destructors take any parameters? It's not that it's a problem that they doesn't. It should be fairly simple to get around. I just don't see any reason to why it wont take any parameters. What am I missing? (:

    And why couldn't pointers which points to objects, just point to an object of whatever class I wanted it to? I mean, the reason pointers which points to for example an int can't be told to point to a long is because the differences in the amount of space the two data types takes up in memory (right?). But since a pointer can be the type BaseClass yet still point to a class made from BaseClass, let's say NewClass. NewClass would be able to hold new data which BaseClass didn't, making it contain more data. Yet the pointer which was created to point towards a BaseClass can still point to NewClass. So why couldn't the pointer just point to whatever object it wanted? Yet again, I suppose I'm missing something.

    Thanks. (:

  2. #2
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by Zigs View Post
    Why doesn't destructors take any parameters? It's not that it's a problem that they doesn't. It should be fairly simple to get around. I just don't see any reason to why it wont take any parameters. What am I missing? (:
    How would you pass parameters to an automatically called destructor?

    And why couldn't pointers which points to objects, just point to an object of whatever class I wanted it to?
    All operations must be statically checked by the compiler. A pointer to a base can point to a derived object because there's still the base object embedded in the derived object. Furthermore, the virtual call mechanism ensures that overrides get to the right function. However, both of these are highly reliant on inheritance. You still can only call functions that exist in the base class.
    What would you do with a pointer to "object" that you can't do with a pointer to void?
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  3. #3
    Registered User
    Join Date
    Dec 2007
    Location
    Denmark
    Posts
    14
    Quote Originally Posted by CornedBee View Post
    How would you pass parameters to an automatically called destructor?
    [Edit]
    Having several destructors using overloaded functions and that way still having the "standard" destructor which would be the one used for automatic calls?
    [\Edit] Sorry, mixed words up >_>
    Quote Originally Posted by CornedBee View Post
    All operations must be statically checked by the compiler. A pointer to a base can point to a derived object because there's still the base object embedded in the derived object. Furthermore, the virtual call mechanism ensures that overrides get to the right function. However, both of these are highly reliant on inheritance. You still can only call functions that exist in the base class.
    True. I suppose it's the way classes/objects works ("behind the scene") I don't understand then. I mean, functions has to be virtual. But variable doesn't for some reason?

    Quote Originally Posted by CornedBee View Post
    What would you do with a pointer to "object" that you can't do with a pointer to void?
    Oh.. What are those? Ah never mind. I'm going to read up on that myself. thanks anyway. (:
    Last edited by Zigs; 12-30-2007 at 07:16 PM. Reason: Making myself clearer..

  4. #4
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Having several destructors using polymorphisms and that way still having the "standard" destructor which would be the one used for automatic calls?
    When a derived class is constructed, first the constructor of the base class runs, then the constructor of the derived class.

    When a derived class is destructed, first the destructor of the derived class runs, then the base class is destructed.

    When you have a polymorphic object (pointer to base), the destructor of base must be virtual, otherwise only the base destructor is called, but not the destructor of derived class.

    That is, you don't pick which parts of a derived class will be destructed and which not. You'll need to destruct the whole object and several destructor calls happen for that.
    Last edited by anon; 12-30-2007 at 07:25 PM.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  5. #5
    Registered User
    Join Date
    Dec 2007
    Location
    Denmark
    Posts
    14
    Quote Originally Posted by anon View Post
    When a derived class is constructed, first the constructor of the base class runs, then the constructor of the derived class.

    When a derived class is destructed, first the destructor of the derived class runs, then the base class is destructed.

    When you have a polymorphic object (pointer to base), the destructor of base must be virtual, otherwise only the base destructor is called, but not the destructor of derived class.
    Very true. But erm.. You see, I mixed words up. I meant to say function overloading instead of polymorphisms (I keep mixing the words up.. >_>").

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Destruction of an object is generally an "all or nothing" process - an object is either being destroyed (after which it no longer exists) or it isn't (in which case, the destructor need not be invoked). There is therefore no need to provide means to supply additional information (i.e. parameters) to guide the process.

    If you have some notion of partial destruction, that would normally be handled by setting state of the object (eg an object in a state in which it behaves in a specific manner in preparation for being destroyed) but the object still exists in some form.

  7. #7
    Registered User
    Join Date
    Dec 2007
    Location
    Denmark
    Posts
    14
    Quote Originally Posted by grumpy View Post
    Destruction of an object is generally an "all or nothing" process - an object is either being destroyed (after which it no longer exists) or it isn't (in which case, the destructor need not be invoked).
    Yes. But the reason we are accessing the the destructor in the first place is because theres something we want done differently. For example if you have a linked list and want to destroy the list itself, the destructor in the node-part of the list would, when running its destructor, pass on the destruction call to the next node. Now imagine that the user would sometimes (sometimes not) want to delete the data object the list points to (supposing that the user is smart enough to remember not to leak the objects). If the destructor would take a simple boolean like DestroyData, there would be CPU power to spare in the way of not having to call another line of functions all the way down the list. in addition the code would be clearer and easier to understand (to me at least). consider this stripped down example:
    Code:
    class Node{
        public:
            ~Node(){
            }
            ~Node(bool DestroyData){
                if(DestroyData){
                    delete my_data;
                }
            }
        private:
            Data * my_data;
    };
    It would work in (non-C++) theory, right?
    Last edited by Zigs; 12-30-2007 at 08:45 PM. Reason: Forgot the function overloading i was talking about before >_>"

  8. #8
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Quote Originally Posted by Zigs View Post
    Yes. But the reason we are accessing the the destructor in the first place is because theres something we want done differently. For example if you have a linked list and want to destroy the list itself, the destructor in the node-part of the list would, when running its destructor, pass on the destruction call to the next node. Now imagine that the user would sometimes (sometimes not) want to delete the data object the list points to (supposing that the user is smart enough to remember not to leak the objects). If the destructor would take a simple boolean like DestroyData, there would be CPU power to spare in the way of not having to call another line of functions all the way down the list. in addition the code would be clearer and easier to understand (to me at least). consider this stripped down example:
    Code:
    class Node{
        public:
            ~Node(){
            }
              ~Node(bool DestroyData){
                if(DestroyData){
                    delete my_data;
                }
            }
        private:
            Data * my_data;
    };
    It would work in (non-C++) theory, right?
    The problem is, objects are almost always destroyed with an implicit call to the destructor, such as when the object goes out of scope, or with a call to delete. In such cases, there is no syntax for passing parameters to the destructor. Only the objects state can be used to determine what to do during destruction. For example the above issue can be solved with a member variable:
    Code:
    class Node{
        public:
            ~Node(){
                if(DestroyData)
                    delete my_data;
            }
        private:
            bool DestroyData;
            Data * my_data;
    };
    The usefulness of having a parameterized destructor is very limited, even if the syntax were added. It is generally good style to have the object be able decide for itself what resources need to be released, and to minimize the need on the client to manually manage resources.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  9. #9
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Why would a node's destructor do anything to another node? It should be the container object holding all the nodes that destroys each node that it contains.

    If you really want to change the behavior of a destructor, you could create member variables that you can change and do something like this:
    Code:
    class Node
    {
    public:
        ~Node()
        {
            if ( m_DeleteNextNode == true )
            {
                delete m_Next;
            }
    
            ...
        }
    
    private:
        Node*  m_Prev;
        Node*  m_Next;
        bool  m_DeleteNextNode;
    };
    But in that example, I believe you could run out of stack space if your list is very long because of the recursive function calls; which is why you'd want another class which just contains the Node pointers and deletes each one individually.

  10. #10
    Registered User
    Join Date
    Dec 2007
    Location
    Denmark
    Posts
    14
    Quote Originally Posted by King Mir View Post
    The problem is, objects are almost always destroyed with an implicit call to the destructor, such as when the object goes out of scope, or with a call to delete. In such cases, there is no syntax for passing parameters to the destructor. Only the objects state can be used to determine what to do during destruction. For example the above issue can be solved with a member variable:
    Code:
    class Node{
        public:
            ~Node(){
                if(DestroyData)
                    delete my_data;
            }
        private:
            bool DestroyData;
            Data * my_data;
    };
    The usefulness of having a parameterized destructor is very limited, even if the syntax were added. It is generally good style to have the object be able decide for itself what resources need to be released, and to minimize the need on the client to manually manage resources.

    True.. This was the sort of reason I was looking for.


    Quote Originally Posted by cpjust View Post
    . . . which is why you'd want another class which just contains the Node pointers and deletes each one individually.
    I see. I am still learning.. and these examples surely made me understand why destructors doesn't take parameters. Thanks to both of you (:

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by anon View Post
    When you have a polymorphic object (pointer to base), the destructor of base must be virtual, otherwise only the base destructor is called, but not the destructor of derived class.
    This is not true, btw. This is true in specific situations.
    If the destructor isn't virtual and you call delete on a derived object, then everything is destructed fine. But if you call delete on a base class object, then only the base class destructor is called! The compiler doesn't make a check to see if base is actually a derived. Thus, we can use polymorphism and virtual functions to make the destructor virtual and the compiler will look up which type of object it is and call the appropriate destructor(s).
    It's usually considered a good idea to make the destructor virtual when dealing with inherited objects and polymorphism to avoid mistakes such only the base class destructor getting called in parts of your program because you forgot that you're calling delete with a base class pointer.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Sometimes, though, you want to inherit publicly from a class just to inherit some functions and functionality, but you don't actually want polymorphism. I'm thinking of implementation helpers and the CRTP in particular.
    What you can do in such a situation is make the base's destructor protected. Then it can be called by the derived destructor, but not from outside the class.

    Thus, the rule is: the destructor of a class that is used as a base class should be either public and virtual or non-virtual and protected.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  13. #13
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Elysia View Post
    This is not true, btw. This is true in specific situations.
    Well, the conundrum is that your statements are both true and misleading. anon's statement was incorrect.

    If we assume a class Derived which is derived from Base, and Base does not have a virtual destructor, then in the code
    Code:
    int main()
    {
        Base *x = new Derived;
        delete x;
    }
    the line "delete x;" yields undefined behaviour.

    In practice, with some compilers, the result is that only Base's destructor is called. But that is only one possibility; there is certainly no guarantee that result will occur with all compilers.

Popular pages Recent additions subscribe to a feed