Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Ναι αλλά θα έχεις leaks! (συ είπας, και σε πιστεύω).

 

Δεν είναι απαραίτητο ότι μια κλάσση πρέπει να υποστηρίζει πολυμορφισμό, ένα παράδειγμα είναι o std::vector, μπορείς να κάνεις inherit από αυτόν μεν, δε μπορείς να τον χρησιμοποιήσεις σαν base class για πολυμορφισμό δε.  Οπότε εφόσον δεν υποστηρίζει πολυμορφισμό θα ήταν ανόητο να έχει virtual destructor μιας και θα πλήρωνε το performance pernalty του late binding χωρίς λόγο.

  • Απαντ. 43
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Δημοφιλείς Ημέρες

Δημοσ.

Ναι αλλά θα έχεις leaks! (συ είπας, και σε πιστεύω).

 

Εξαρταται απο την χρηση. Δηλαδη αν ποτε δεν χρησημοποιεις την class σαν βαση που κατοπιν θα κανεις delete πανω σε αυτην εισαι απολυτα safe. Ειπα για παραδειγμα την std::vector. Δες το implementation...  Ο destructor ειναi non-virtual οποτε δεν συνιστατε να κανεις extend το vector (η το map η οποιονδηποτε αλλον container)... 

 

Αντιθετα, μια κλαση που ειναι σχεδιασμενη σαν βαση, θα εχει τον destructor virtual. Δες για παραδειγμα

 

boost:bad_lexical_cast η boost::placeholder

 

 

Προσεξε, οτι υπαρχουν και εξαιρεσεις στον κανονα!

 

Σαν παραδειγμα τετοιας εξαιρεσης θα παρεις την boost::noncopyuable. Προσπαθησε να καταλαβεις γιατι σε αυτη την περιπτωση δεν οριζεται ο destructor ως virtual παροτι η κλαση θα αποτελεσει βαση...

Δημοσ.

Εξαρταται απο την χρηση.

:blink: ...Μήπως υποννοείς ότι τελικά δεν ισχύει αυτό:

 

Οταν γραφεις μια base class πρεπει να κανεις τον destructor virtual

;;;

Δημοσ.

:blink: ...Μήπως υποννοείς ότι τελικά δεν ισχύει αυτό:

 

;;;

 

Μια κλαση δεν ειναι υποχρεωτικα παντα σχεδιασμενη να αποτελεσει base class.

 

Μπορει να ειναι stand alone.  Αυτος ειναι ενας απο τους λογους της εισαγωγης του final keyword..

 

 

 

Ο τροπος που θα κανεις destruct ειναι μια απο τις πολυπλοκοτητες της C++ που την κανουν δυσχρηστη, και ενας τομεας που θα πρεπει να σκεφτεις πολυ καλα οταν γραφεις ενα framework.

 

Σαν παραδειγμα θα αναφερω το COM. Οσοι εχουμε ασχοληθει με αυτο, ξερουμε οτι η βαση για ολα τα interfaces ειναι το IUnknown, το οποιο σε C++ γινεται declared ετσι:

 

class IUnknown
{
public:
   virtual HRESULT QueryInterface(REFID riid, void** ppv)=0;
   virtual ULONG AddRef () = 0;
   virtual ULONG Release() = 0;
};

Δες οτι ο IUnknown παροτι η βαση ολων των interfaces, δεν εχει virtual destructor!

 

Εχει ομως την Release η οποια καλειται απο το SCM οταν το reference count γινει μηδεν και καθαριζει την μνημη...  Ειναι δηλαδη αυτος ενας τροπος για garbage collection παροτι πολυ πιο complicated απο οτι σε γλωσσες με ενσωματομενο GC οπως πχ Java η C#...

 

Στην περιπτωση του COM, το βασικο contract δηλαδη, δεν γνωριζει τις λεπτομερειες του memory allocation, οι οποιες γινονται implement σε χαμηλοτερο επιπεδο, απο το ιδιο το component... Αυτος ο σχεδιασμος δινει ολη την απαιτουμενη ευελιξια, στον τροπο που θα χειριστουμε την μνημη αναλογα με τις αναγκες μας.  Μπορει δηλαδη να χρησιμοποιησουμε εσωτερικα κατι τοσο απλο (και επικινδυνο) σαν raw new και delete, η να κανουμε overload τον new operator η ακομα και να χρησιμοποιησουμε static memory pools...  

 

Παρατηρησε επισης, οτι στην περιτωση αυτη του IUnknown, ο user συμφωνει να μην καλεσει ποτε το delete σε explicit fashion, αλλα οταν το object του πηγαινει out of scope απλα καλει το Release...

Δημοσ.

Μια κλαση δεν ειναι υποχρεωτικα παντα σχεδιασμενη να αποτελεσει base class.

 

Μπορει να ειναι stand alone.  Αυτος ειναι ενας απο τους λογους της εισαγωγης του final keyword..

Ναι. Η σύμβαση είναι ότι οτιδήποτε δεν είναι final, είναι σχεδιασμένο να είναι base class. Έστω και δυνητικά.

Με άλλα λόγια, οτιδήποτε δεν απαγορεύεται ρητά, επιτρέπεται by default.

 

Ερώτηση (πραγματικά δεν ξέρω): Η std::vector είναι final ή όχι;

 

Quiz: Αν κάνω τον destructor της base class nonvirtual και protected, πόσα γατάκια θα πεθάνουν;

Ή δεν θα είχα ποτέ κανέναν λόγο να κάνω κάτι τέτοιο; (cheat)

Δημοσ.

Ναι. Η σύμβαση είναι ότι οτιδήποτε δεν είναι final, είναι σχεδιασμένο να είναι base class. Έστω και δυνητικά.

Με άλλα λόγια, οτιδήποτε δεν απαγορεύεται ρητά, επιτρέπεται by default.

 

Ερώτηση (πραγματικά δεν ξέρω): Η std::vector είναι final ή όχι;

 

Quiz: Αν κάνω τον destructor της base class nonvirtual και protected, πόσα γατάκια θα πεθάνουν;

Ή δεν θα είχα ποτέ κανέναν λόγο να κάνω κάτι τέτοιο; (cheat)

 

 

To αν std::vector θα ειναι final η οχι οπως και το αν θα εχει virtual desctructor ειναι implementor specific details. Απο οσο ξερω SGI, Microsofts κλπ δεν οριζουν το vector η αλλον container σαν final.  Αυτο δεν αποτελει εκπληξη, καθως και απο το παρελθον ποτε δεν ειδα ουτε ενα library να χρησιμοποιει το idiom που απαγορευει το derivation απο μια κλαση αλλα απλα και μονο η υπαρξη του non- virtual desctructor ηταν και ειναι αρκετη να σηματοδοτησει την μη χρηση της κλασης σαν βαση μιας ιεραρχιας...

 

 

Ενας λογος να κανεις protected τον destructor ειναι για να κοντρολαρεις το destruction ενος singleton

 

In my company we make the destructor protected and then provide a static public function to delete the singleton object, the in same way that you normally provide a static public function to allocate and gain access to the object.

 

Οσον αφορα τον private destructor, μια χρηση ειναι η παρακατω:

#include <iostream>
#include <vector>

template<typename T>
class Pool {
    std::vector<T*> _pool;
public:
    ~Pool() {
        for(auto t: _pool){
            delete t;
        }
    }
    void push_back(T* t) {_pool.push_back(t);}

};

class A {
        ~A() { std::cout << "desctructor" << std::endl;}
        A() {}
        friend class Pool<A>;
        static Pool<A>  _pool;
    public:
        static A* make() {
            A* p = new A();
            _pool.push_back(p);
            return p;
        }
};

Pool<A> A::_pool;

int main() {
    A* a = A::make();
    A* a1 = A::make();
    A* a2 = A::make();
    //delete a; δεν μπορεις να κανεις explicit delete !
    // οταν ομως το προγραμμα σου τελειωσει, αυτοματα ολοι οι A pointers θα γινουν delete...
}
Δημοσ.

Ενας λογος να κανεις protected τον destructor ειναι για να κοντρολαρεις το destruction ενος singleton

Βρε αδερφέ...

Τελικά υπάρχουν ή δεν υπάρχουν τρόποι (και λόγοι) για να ορίσεις ένα destructor μίας base class να είναι nonvirtual;

...Χωρίς να έρθει ο κόσμος ανάποδα;;;

 

Η ερώτηση είναι σαφής. Προσωπικά, θα ήμουν ευχαριστημένος ακόμα και με μία μονολεκτική απάντηση.

Δημοσ.

Η ερώτηση είναι σαφής. Προσωπικά, θα ήμουν ευχαριστημένος ακόμα και με μία μονολεκτική απάντηση.

 

Ναι.

 

Αλλά ρε παιδί μου πραγματικά δε διευκολύνεις την κουβέντα.

 

Επίσης, για τη σύμβαση που λες παραπάνω. Μην είσαι τόσο απόλυτος. Η List<T> σε .ΝΕΤ δεν είναι για να την κάνεις inherit, και επίσης δεν είναι sealed. Γιατί; Ε γιατί τι να κάνουμε τώρα. Και δε μιλάμε για καμιά class του πεταμού αλλά για την αντίστοιχη std::vector.

Δημοσ.

Ναι.

 

I rest my case.

 

Αλλά ρε παιδί μου πραγματικά δε διευκολύνεις την κουβέντα.

Γιατί το λες αυτό;;;

Εγώ, ένα "γιατί" ρώτησα (μάλλον δύο) και μας πήρε δύο σελίδες για να αποδειχθεί τελικά ότι θα έπρεπε να είναι και οι δύο ερωτήσεις ρητορικές!

Εγώ φταίω;

 

Επίσης, για τη σύμβαση που λες παραπάνω. Μην είσαι τόσο απόλυτος. Η List<T> σε .ΝΕΤ δεν είναι για να την κάνεις inherit, και επίσης δεν είναι sealed. Γιατί; Ε γιατί τι να κάνουμε τώρα. Και δε μιλάμε για καμιά class του πεταμού αλλά για την αντίστοιχη std::vector.

Όταν λες "δεν είναι για να την κάνεις inherit", εννοείς ότι θα χτυπήσει ο compiler ή you must use the force;

(από .NET είμαι ψιλοάσχετος)

Δημοσ.

 

Γιατί το λες αυτό;;;

Εγώ, ένα "γιατί" ρώτησα (μάλλον δύο) και μας πήρε δύο σελίδες για να αποδειχθεί τελικά ότι θα έπρεπε να είναι και οι δύο ερωτήσεις ρητορικές!

Εγώ φταίω;

 

 

Το θεμα του virtual desctructor οσον αφορα την base class, εχει σαφεστατα απαντηθει και αποτελει βασικη γνωση της C++. 

 

Υπαρχουν δεκαδες σχετικα references οπως πχ:

 

http://www.parashift.com/c++-faq/virtual-dtors.html

http://www.cprogramming.com/tutorial/constructor_destructor_ordering.html

http://software.intel.com/sites/products/documentation/doclib/iss/2013/sa-ptr/sa-ptr_win_lin/GUID-41408AE0-841E-4E73-9A3B-5AC183F488F2.htm

 

και πολλα αλλα..

 

Για μια πληρη αναφορα στο θεμα δες εδω:

 

http://knot805.eti.pg.gda.pl/po/books/Effective_C++,%20Second%20Edition_190.pdf

 

Item 14: Make sure base classes have virtual destructors

 

 

Υπαρχουν και μερικες εξαιρεσεις, οι οποιες αναφερθηκαν παραπανω, και εχουν να κανουν με τον τροπο χρησης της κλασης, ειδικα οταν το destruction ΔΕΝ ΠΡΟΟΡΙΖΕΤΑΙ ΝΑ ΓΙΝΕΙ με απευθειας delete. Σαν γενικο κανονα παντως, μεχρι να κατανοησεις αυτες τις σπανιες ειδικες περιπτωσεις (οι οποιες χρησιμευουν και σαν ενα εμμεσο τροπo documentation, δεχνωντας στον user πχ οτι δεν θα πρεπει να κανει delete μεσω μιας βασης χωρις virtual constructor) μπορεις να χρησιμοποεις το idiom του virtual desctructor σε ΟΛΕΣ τις κλασεις που προοριζεις για βασεις μιας ιεραρχιας...

 

Βρε αδερφέ...

Τελικά υπάρχουν ή δεν υπάρχουν τρόποι (και λόγοι) για να ορίσεις ένα destructor μίας base class να είναι nonvirtual;

...Χωρίς να έρθει ο κόσμος ανάποδα;;;

 

Η ερώτηση είναι σαφής. Προσωπικά, θα ήμουν ευχαριστημένος ακόμα και με μία μονολεκτική απάντηση.

 

 

Φυσικα υπαρχει τροπος να ορισεις τον destructor μιας base class σαν nonvirtual. To θεμα δεν ειναι αν υπαρχει ο τροπος αυτος αλλα το οτι αυτη η προσεγγιση πρεπει να αποφευγεται γιατι δημιουργει προβλημα με το memory leak. Τι ειναι αυτο που σε κανει να επιμενεις στην ερωτηση σου?

Δημοσ.

Το θεμα του virtual desctructor οσον αφορα την base class, εχει σαφεστατα απαντηθει και αποτελει βασικη γνωση της C++. 

 

Υπαρχουν δεκαδες σχετικα references οπως πχ:

 

Ειλικρινά πιστεύεις ότι χρειάζομαι κανένα link για να δω τι λένε αυτοί που έχουν ασχοληθεί με το θέμα;

Νομίζεις δηλαδή ότι η ερώτησή μου ήταν για να μου δείξεις, ή να μάθω τι ισχύει;

 

Όχι φίλε μου, ο σκοπός ήταν να αμφισβητήσω ένα δόγμα, μία υπεργενίκευση που αναπαράγεται άκριτα, επειδή κάποιος το διάβασε στα specs ή σε κάποιο από τα links που παραθέτεις.

 

Εδώ μέσα υπάρχουν και άνθρωποι που θέλουν να μάθουν, και υποθέτω ότι και οι ίδιοι προτιμούν να μάθουν να σκέφτονται και όχι να παπαγαλίζουν. Επομένως όταν λέμε κάτι, θα πρέπει να το παρουσιάζουμε αντικειμενικά και σφαιρικά, με όλες τις εξαιρέσεις, ακόμα κι αν αυτές είναι αμελητέες.

 

Το να λες "Οταν γραφεις μια base class πρεπει να κανεις τον destructor virtual" είναι δογματικό. Πολύ παραπάνω όταν δεν εξηγείς το "γιατί", ώστε να μπορεί αυτός που το διαβάζει να κρίνει αν η θεωρία σου στέκει. Κάποιος λοιπόν έπρεπε να το αμφισβητήσει...

 

Φυσικα υπαρχει τροπος να ορισεις τον destructor μιας base class σαν nonvirtual. To θεμα δεν ειναι αν υπαρχει ο τροπος αυτος αλλα το οτι αυτη η προσεγγιση πρεπει να αποφευγεται γιατι δημιουργει προβλημα με το memory leak. Τι ειναι αυτο που σε κανει να επιμενεις στην ερωτηση σου?

Το γεγονός ότι δεν είχα πάρει μέχρι τώρα σαφή απάντηση, φυσικά. Τι άλλο;

Δημοσ.

 

Ειλικρινά πιστεύεις ότι χρειάζομαι κανένα link για να δω τι λένε αυτοί που έχουν ασχοληθεί με το θέμα;

Αυτο μου δινεις να καταλαβω, ειδικα οταν μιλαμε για ενα προφανες θεμα το οποιο εχει απαντηθει εδω και δεκαετιες στο οποιο δειχνεις να αντιδρας χωρις επιχειρηματα και θεσεις...

 

Το να λες "Οταν γραφεις μια base class πρεπει να κανεις τον destructor virtual" είναι δογματικό. Πολύ παραπάνω όταν δεν εξηγείς το "γιατί", ώστε να μπορεί αυτός που το διαβάζει να κρίνει αν η θεωρία σου στέκει. Κάποιος λοιπόν έπρεπε να το αμφισβητήσει...

 

Αυτα που λες ειναι περι δογματος κλπ ειναι απλα αμπελοφιλοσοφιες...  Σε παραπεμπω στο βιβλιο του Mayers που λεει ακριβως αυτα που ειπα εγω,θελεις να αμβισβητησεις και αυτον μηπως?... Οπως καταλαβαινεις δεν προκειται περι θεωριας μου αλλα περι της κρατουσας αποψης που ακομα και ενας αρχαριος στην C++ πρεπει να γνωριζει...  Οσο για το γιατι το εξηγησαμε απο το πρωτο post...

 

Αυτα και τελειωνω με το συγκεκριμενο θεμα ._

Δημοσ.

Αυτο μου δινεις να καταλαβω, ειδικα οταν μιλαμε για ενα προφανες θεμα το οποιο εχει απαντηθει εδω και δεκαετιες στο οποιο δειχνεις να αντιδρας χωρις επιχειρηματα και θεσεις...

Αυτό κατάλαβες; Ok then...

 

Αυτα που λες ειναι περι δογματος κλπ ειναι απλα αμπελοφιλοσοφιες...

...Εχμ... Γιατί; B)

Δημοσ.

 

Συμφωνω με τον geomagas. Η αληθεια ειναι (το λεω εγω που ξερω τα παντα) οτι δεν μας ενδιαφερει εαν η class ειναι base ή ξερω γω τι αλλο για να μαρκαρουμε τον destructor της με το virtual keyword. Μαρκαρουμε ως virtual εκεινον τον destructor που θελουμε να γινει override.

 

Τωρα που εγραψα override, να πω οτι υπαρχει νεο keyword στη c++11. Το "override" το οποιο μπορει να μας βγαλει απο περιεργες καταστασεις. πχ https://ideone.com/PNZE0l

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα

  • Δημιουργία νέου...