DeltaLover Δημοσ. 22 Ιουλίου 2016 Δημοσ. 22 Ιουλίου 2016 -Δεν τον έκανα virtual γιατί δεν έχει derived classes. Ναι, άλλα το ότι ο δικός σου κώδικας δεν έχει derived classes από το vector σου, αυτό δεν σημαίνει πως ο χρήστης σου δεν θα προσπαθήσει να κάνει κάτι τέτοιο, ανοίγοντας έτσι το ενδεχόμενο για memory leak αν κάνει delete σε pointer του derived class. Μπορείς βέβαια να μου πεις ότι τα STL implementations κάνουν ακριβώς αυτό που κάνεις κι εσύ Ο επίσημος λόγος που γίνεται αυτό υποτίθεται ότι είναι η παράλειψη του v-table που αυτόματα αυξάνει το μέγεθος των αντικειμένων σου κρατώντας τις διεύθυνσης στα virtual pointers. Αν θέλεις να ακολουθήσεις αυτή την μέθοδο, θα πρέπει η να το εξηγήσεις σε comments η να βρεις κάποιο τρόπο να απαγορεύσεις το derivation από την κλάση σου (όπως πχ στην Java το final η στην C# το sealed). Μπορείς να δεις πως κάτι τέτοιο μπορεί να επιτευχθεί με standard C++?
Moderators Kercyn Δημοσ. 22 Ιουλίου 2016 Moderators Δημοσ. 22 Ιουλίου 2016 Μπορείς να δεις πως κάτι τέτοιο μπορεί να επιτευχθεί με standard C++? Και στη C++ υπάρχει final. (kaliakman μην ανοίξεις το spoiler αν δεν ξέρεις την απάντηση σ' αυτό που λέει ο DeltaLover) 1
DeltaLover Δημοσ. 22 Ιουλίου 2016 Δημοσ. 22 Ιουλίου 2016 Και στη C++ υπάρχει final. (kaliakman μην ανοίξεις το spoiler αν δεν ξέρεις την απάντηση σ' αυτό που λέει ο DeltaLover) Ναι οσον αφορα C++ 11. Μπορουμε επισης να επιτυχουμε παρομοιο effect και στην παλαιοτερη C++..
Moderators Kercyn Δημοσ. 22 Ιουλίου 2016 Moderators Δημοσ. 22 Ιουλίου 2016 Ναι οσον αφορα C++ 11. Μπορουμε να επιτυχουμε παρομοιο effect και στην παλαιοτερη C++ ομως.. Κάτι τέτοιο λες; Δεν το ήξερα καν ότι γινόταν αυτό. Τελικά γίνεσαι πολύ εφευρετικός άμα δε σου δίνει η γλώσσα κάτι που χρειάζεσαι... 2
DeltaLover Δημοσ. 22 Ιουλίου 2016 Δημοσ. 22 Ιουλίου 2016 Κάτι τέτοιο λες; Δεν το ήξερα καν ότι γινόταν αυτό. Τελικά γίνεσαι πολύ εφευρετικός άμα δε σου δίνει η γλώσσα κάτι που χρειάζεσαι... Βεβαιως. Μια απο τις κλασικες εφαρμογες του virtual inheritance και ενα απο τα πολυ συνηθισμενα θεματα C++ interview... Βεβαια δεν εναι ακριβως το ιδιο με το final keyword καθως το compile time exception θα γινει raised μονο αν προσπαθησουμε να κανουμε instantiate την κλαση.
παπι Δημοσ. 23 Ιουλίου 2016 Δημοσ. 23 Ιουλίου 2016 Προσπαθώ να φτιάξω ένα custom vector με ελάχιστο functionality μιας και θα μου χρειαστεί το χειμώνα γιατί απαγορεύεται( ) τουλάχιστον στις πρώτες ασκήσεις του μαθήματος(OOP) χρήση vector και γενικά STL. Δουλεύει κανονικά για όσα δοκίμασα εκτός από string! Δοκίμασα δηλαδή στην αρχή να φτιάξω μια κλάση που έχει μόνο ένα string με ένα getter/setter αλλά έτρωγα segmentation στο reallocate όταν έκανα delete το αρχικό array. Δοκίμασα μετά ένα απλό string γιατί υπέθεσα οτί κάτι θα φταίει με την κλάση μιας και με άλλους standard types δούλευε κανονικά αλλά μάταια μιας και εκεί είχα το ίδιο πρόβλημα. Έχει κανείς καμία ιδέα τι μπορεί να φταίει μιας και το Google δεν βοήθησε πολύ. Site: https://github.com/EvanKaraf/CustomVector.git">Git Οταν κανεις delete το array, καλεις τους destructors των items. Σε πραματα που δεν εχει καποια επιπτωση ο destructor πχ int, δεν θα εχεις προβλημα, σε αλλα που εχει, πχ ο ιδιος σου vector, θα εχεις προβλημα. Το σωστο ειναι να κανεις copy και οχι memcpy. Ετσι ωστε να γινει shallow copy του string.
moukoublen Δημοσ. 23 Ιουλίου 2016 Δημοσ. 23 Ιουλίου 2016 Κάθε item δείχνει στην προηγούμενη θέση του την οποία κάνω delete? και μετά όταν κανω delete καλείται ο destructor απο δυο διαφορετικά σημεία και γίνεται ....? class Foo{ public: int* arrPointer; Foo() { arrPointer = new int[4]; } ~Foo() { delete[] arrPointer; } } Foo one; //Παράδειγμα δεδομένων /* one.arrPointer : 0x10 * * 0x10 | 0x11 | 0x12 | 0x13 [memory address] * ----------------------------------- * 145 | 123 | 543 | 323 [memory content] τυχαίες τιμές * ----------------------------------- */ Foo two; /* two.arrPointer : 0x20 * * 0x20 | 0x21 | 0x22 | 0x23 [memory address] * ----------------------------------- * 965 | 765 | 267 | 222 [memory content] τυχαίες τιμές * ----------------------------------- */ Ας πάμε βήμα βήμα. 2 διαφορετικά instances του παραπάνω. Καταλαβαίνουμε μέχρι εδώ ότι το κάθε instance θα έχε ενα στοιχείο arrPointer τύπου int pointer όπου το arrPointer του κάθε instance θα δείχνει σε ένα διαφορετικό array. Σωστά; Αν δεν είμαστε σίγουροι για το παραπάνω πρέπει να διαβάσουμε λίγο περισσότερο τους pointers. Τώρα αν εγώ κάνω αυτό: two.arrPointer = one.arrPointer Τι έχω κάνει; Έχω αντιγράψει τα περιεχόμενα που ενός array στο άλλο; Δηλαδή μετά απο αυτή τη γραμμή το two.arrPointer θα έχει την τιμή που είχε (0x20) αλλά περιεχόμενα στις τέσσερις αυτές θέσεις θα είναι τα ίδια με αυτά απο τη θέση 0χ10; Η απάντηση είναι ενα τεράστιο όχι. Μετά απο αυτή τη γραμμή και οι 2 pointers θα έχουν την τιμή 0x10. Άρα θα δείχνουν στο ίδιο σημείο! Αν το καταλάβαμε μέχρι εδώ πάμε στο επόμενο. κάνω τώρα delete one; Τι θα γίνει στο delete του one? Και πως αυτό επηρεάζει το two? 1
kaliakman Δημοσ. 23 Ιουλίου 2016 Μέλος Δημοσ. 23 Ιουλίου 2016 class Foo{ public: int* arrPointer; Foo() { arrPointer = new int[4]; } ~Foo() { delete[] arrPointer; } } Foo one; //Παράδειγμα δεδομένων /* one.arrPointer : 0x10 * * 0x10 | 0x11 | 0x12 | 0x13 [memory address] * ----------------------------------- * 145 | 123 | 543 | 323 [memory content] τυχαίες τιμές * ----------------------------------- */ Foo two; /* two.arrPointer : 0x20 * * 0x20 | 0x21 | 0x22 | 0x23 [memory address] * ----------------------------------- * 965 | 765 | 267 | 222 [memory content] τυχαίες τιμές * ----------------------------------- */ Ας πάμε βήμα βήμα. 2 διαφορετικά instances του παραπάνω. Καταλαβαίνουμε μέχρι εδώ ότι το κάθε instance θα έχε ενα στοιχείο arrPointer τύπου int pointer όπου το arrPointer του κάθε instance θα δείχνει σε ένα διαφορετικό array. Σωστά; Αν δεν είμαστε σίγουροι για το παραπάνω πρέπει να διαβάσουμε λίγο περισσότερο τους pointers. Τώρα αν εγώ κάνω αυτό: two.arrPointer = one.arrPointer Τι έχω κάνει; Έχω αντιγράψει τα περιεχόμενα που ενός array στο άλλο; Δηλαδή μετά απο αυτή τη γραμμή το two.arrPointer θα έχει την τιμή που είχε (0x20) αλλά περιεχόμενα στις τέσσερις αυτές θέσεις θα είναι τα ίδια με αυτά απο τη θέση 0χ10; Η απάντηση είναι ενα τεράστιο όχι. Μετά απο αυτή τη γραμμή και οι 2 pointers θα έχουν την τιμή 0x10. Άρα θα δείχνουν στο ίδιο σημείο! Αν το καταλάβαμε μέχρι εδώ πάμε στο επόμενο. κάνω τώρα delete one; Τι θα γίνει στο delete του one? Και πως αυτό επηρεάζει το two? Φίλε μου έχω κατάλαβει pointers. Όταν κάνεις delete θα καθαρίσει η μνήμη από 0χ10 μεχρι 0χ13 και ναι μεν θα δείχνει ακόμα στο 0χ10 o pointer αλλά εκεί πλέον θα υπάρχουν σκουπίδια . Από την στιγμή που έγραψες two.arrPointer = one.arrPointer Έχασες το array του two και υπάρχει memory leak. Τέλος εφόσον έχεις κάνει delete το one και το two δείχνει στο ίδιο σημείο τότε και ο δικός του pointer δείχνει σε σκουπίδια. Σωστά μέχρι εδώ;
moukoublen Δημοσ. 24 Ιουλίου 2016 Δημοσ. 24 Ιουλίου 2016 Δεν είναι μόνο ότι θα δείχνει σε σκουπίδια. Έχεις crash αν πας να γράψεις και μπορεί και να διαβάσεις από χώρο που έχει ελευθερωθεί. Το ίδιο πράγμα με το one.arrPointer = two.arrPointet γίνεται αν κάνεις memcpy το ένα instance στο άλλο (to one στο two). Αντιγράφεται δυαδικά το ένα instance στο άλλο και άρα οι 2 pointers δείχνουν μετά στο ίδιο σημείο. Άρα αν κανεις delete το ένα instance, boom. Τώρα... Ακριβώς αυτό κάνεις όταν κανεις memcpy τον ένα πίνακα στον άλλο. Αντιγράφεται δυαδικά ένα ένα instance από τον ένα πίνακα στον άλλο. Όταν λοιπόν οι πίνακες σου είναι κάτι άλλο πέρα απο απλοί τύποι δεδομένων τότε μπορεί να γίνουν όλα αυτά που είπαμε παραπάνω. Το string λοιπόν είναι ενα τέτοιο αντικείμενο. Εσωτερικά έχει pointers και δυναμική δέσμευση μνήμης. Ποτέ δεν αντιγράφουμε το string αντικείμενο (και γενικά κανένα αντικείμενο αν θέλουμε να είμαστε ασφαλείς και όχι να φλερταρουμε με crash) με memcpy.
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα