cpp:object_lifecycle
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
cpp:object_lifecycle [2020/04/14 08:51] – gthanos | cpp:object_lifecycle [2020/04/14 14:29] – [Ένα ακόμη πιο σύνθετο παράδειγμα αρχικοποίησης δεικτών] gthanos | ||
---|---|---|---|
Line 2: | Line 2: | ||
====== Κύκλος ζωής των αντικειμένων - Δημιουργία και ανάθεση αντικειμένων στο heap ====== | ====== Κύκλος ζωής των αντικειμένων - Δημιουργία και ανάθεση αντικειμένων στο heap ====== | ||
- | Τα αντικείμενα που φτιάξαμε μέχρι τώρα αποθηκεύονται μέσα στη στοίβα (//stack//) της συνάρτησης που | + | Παρακάτω δίνεται ο κώδικας της κλάσης //Rectangle// τον οποίο θα χρησιμοποιήσουμε για να μεταγλωττίσουμε |
- | + | ||
- | Παρακάτω δίνεται ο κώδικας | + | |
<code cpp Rectangle.hpp> | <code cpp Rectangle.hpp> | ||
- | using namespace std; | ||
class Rectangle { | class Rectangle { | ||
Line 29: | Line 26: | ||
#include < | #include < | ||
#include " | #include " | ||
+ | |||
+ | using namespace std; | ||
Rectangle:: | Rectangle:: | ||
Line 63: | Line 62: | ||
int Rectangle:: | int Rectangle:: | ||
</ | </ | ||
+ | |||
+ | <WRAP tip 80% round> | ||
+ | Παρατηρήστε τον τρόπο με τον οποίο καλείται κατασκευαστής χωρίς ορίσματα από τους άλλους κατασκευαστές. Η κλήση ενός κατασκευαστή από έναν άλλο είναι δυνατή στη C++ με χρήση του ονόματος της κλάσης. Γενικότερα, | ||
+ | <code cpp> | ||
+ | Rectangle:: | ||
+ | *width_ptr = w; | ||
+ | *height_ptr = h; | ||
+ | cout << " | ||
+ | } | ||
+ | </ | ||
+ | ή ισοδύναμα | ||
+ | <code cpp> | ||
+ | Rectangle:: | ||
+ | Rectangle(); | ||
+ | *width_ptr = w; | ||
+ | *height_ptr = h; | ||
+ | cout << " | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ===== 1η Περίπτωση - Δημιουργία αντικειμένων στο Stack ===== | ||
+ | |||
+ | Τα αντικείμενα στο τρέχον παράδειγμα αποθηκεύονται μέσα στη στοίβα (//stack//) της συνάρτησης που καλεί τον κατασκευαστή της. Τα αντικείμενα αυτά έχουν χρόνο ζωής όσο εκτελείται η συγκεκριμένη συνάρτηση και η στοίβα της είναι ενεργή. Μόλις επιστρέψουμε από την συνάρτηση που δημιουργεί το οποιοδήποτε αντικείμενο, | ||
+ | |||
+ | Παρακάτω δίνεται ο κώδικας της συνάρτησης //foo// η οποία δημιουργεί ένα πίνακα από δύο αντικείμενα τύπου // | ||
<code cpp foo.cpp> | <code cpp foo.cpp> | ||
Line 83: | Line 108: | ||
</ | </ | ||
- | Ακολουθεί το σχηματικό διάγραμμα του //stack// της διεργασίας πριν, κατά τη διάρκεια και μετά την εκτέλεσης της συνάρτησης //foo//. | + | Ακολουθεί το σχηματικό διάγραμμα του //stack// της διεργασίας πριν, κατά τη διάρκεια και μετά την εκτέλεσης της συνάρτησης //foo//. Μεταγλωττίζοντας και εκτελώντας τον παραπάνω κώδικα, |
{{ : | {{ : | ||
- | Υπάρχουν | + | ===== 2η Περίπτωση - Δημιουργία αντικειμένων στο Heap ===== |
+ | |||
+ | Υπάρχουν περιπτώσεις που θέλουμε να ορίσουμε ένα αντικείμενο το οποίο θα παραμείνει και μετά την έξοδο από τη συνάρτηση που το δημιούργησε. Σε αυτές τις περιπτώσεις | ||
<code cpp foo.cpp> | <code cpp foo.cpp> | ||
Line 95: | Line 122: | ||
Rectangle* foo(int w, int h) { | Rectangle* foo(int w, int h) { | ||
- | Rectangle *rect_ptr = new Rectangle {w,h}; | + | Rectangle* rect_ptr = new Rectangle {w,h}; |
return rect_ptr; | return rect_ptr; | ||
} | } | ||
Line 101: | Line 128: | ||
int main() { | int main() { | ||
int x=5, y=3; | int x=5, y=3; | ||
- | Rectangle *rect = foo(x,y); | + | Rectangle* rect = foo(x,y); |
cout << "x: " << x << ", y: " << y << endl; | cout << "x: " << x << ", y: " << y << endl; | ||
cout << "area : " << rect-> | cout << "area : " << rect-> | ||
Line 108: | Line 135: | ||
</ | </ | ||
- | Ακολουθεί το σχηματικό διάγραμμα του //stack// και του //heap// της διεργασίας πριν, κατά τη διάρκεια και μετά την εκτέλεσης της συνάρτησης //foo//. | + | Όταν δεν χρειαζόμαστε πλέον το αντικείμενο που δεσμεύτηκε δυναμικά στο //heap// θα πρέπει να το καταστρέψουμε ελευθερώνοντας τη δεσμευμένη μνήμη με τη βοήθεια του τελεστή //delete//. Κατά την |
+ | |||
+ | Ακολουθεί το σχηματικό διάγραμμα του //stack// και του //heap// της διεργασίας πριν, κατά τη διάρκεια και μετά την εκτέλεσης της συνάρτησης //foo//. Στο διάγραμμα δεν αποτυπώνεται η δέσμευση μνήμης για τα πεδία //width// και //height// του κάθε αντικειμένου τύπου //Rectangle//. | ||
{{ : | {{ : | ||
- | ===== Παράδειγμα αρχικοποίησης δεικτών ===== | + | ===== Ένα πιο σύνθετο παράδειγμα αρχικοποίησης δεικτών ===== |
- | Παρακάτω δίνεται η κλάση // | + | Παρακάτω δίνεται η κλάση // |
- | - ο δείκτης //r1// δείχνει στο αντικείμενο | + | - ο δείκτης //r1// δείχνει στο αντικείμενο |
- ο δείκτης //r2// δείχνει σε ένα αντικείμενο που αρχικοποιείται στο //heap//. | - ο δείκτης //r2// δείχνει σε ένα αντικείμενο που αρχικοποιείται στο //heap//. | ||
- ο δείκτης //r3// δείχνει σε ένα πίνακα από αντικείμενα που αρχικοποιείται επίσης στο //heap//. | - ο δείκτης //r3// δείχνει σε ένα πίνακα από αντικείμενα που αρχικοποιείται επίσης στο //heap//. | ||
- | | + | - πριν την ολοκλήρωση του προγράμματος πρέπει να ελευθερώσουμε τη μνήμη που δεσμεύτηκε στο //heap// κατά τη δημιουργία των αντικειμένων στα οποία δείχνουν οι δείκτες //r2, r3 και r4//. |
- | | + | |
- | <WRAP tip 80% round> | + | <code cpp RectangleUsage1.cpp> |
- | Παρατηρήστε τον τρόπο με τον οποίο καλείται κατασκευαστής χωρίς ορίσματα από τους άλλους κατασκευαστές. Η κλήση ενός κατασκευαστή από έναν άλλο είναι δυνατή στη C++ με χρήση του ονόματος της κλάσης. Γενικότερα, | + | |
- | <code cpp> | + | |
- | Rectangle:: | + | |
- | *width_ptr = w; | + | |
- | *height_ptr = h; | + | |
- | cout << " | + | |
- | } | + | |
- | </ | + | |
- | ή ισοδύναμα | + | |
- | <code cpp> | + | |
- | Rectangle:: | + | |
- | Rectangle(); | + | |
- | *width_ptr = w; | + | |
- | *height_ptr = h; | + | |
- | cout << " | + | |
- | } | + | |
- | </ | + | |
- | </ | + | |
- | + | ||
- | <code cpp RectangleUsage.cpp> | + | |
#include < | #include < | ||
using namespace std; | using namespace std; | ||
#include " | #include " | ||
+ | |||
+ | /* Δημιουργώ ένα αντικείμενο ' | ||
+ | * 1. ένα δείκτη που δείχνει στο ' | ||
+ | * 2. ένα δείκτη που δείχνει σε ένα δυναμικά | ||
+ | | ||
+ | * 3. ένα δείκτη που δείχνει σε δυναμικά | ||
+ | | ||
+ | * */ | ||
int main() { | int main() { | ||
- | Rectangle | + | Rectangle |
Rectangle *r1, *r2, *r3; | Rectangle *r1, *r2, *r3; | ||
- | r1 = ▭ | + | |
+ | | ||
+ | cout << "--- init r2 ---" << endl; | ||
r2 = new Rectangle {2}; | r2 = new Rectangle {2}; | ||
- | r3 = new Rectangle[2] { {3,4}, {5} }; | + | |
+ | | ||
| | ||
cout << " | cout << " | ||
- | | + | cout << "r' |
- | r4 = new Rectangle*[2]; | + | |
- | r4[0] = new Rectangle {6}; | + | |
- | r4[1] = new Rectangle (2,6); | + | |
- | + | ||
- | cout << " | + | |
- | | + | |
cout << " | cout << " | ||
cout << " | cout << " | ||
cout << " | cout << " | ||
cout << " | cout << " | ||
- | cout << " | ||
- | cout << " | ||
| | ||
cout << " | cout << " | ||
Line 172: | Line 183: | ||
delete[] r3; | delete[] r3; | ||
| | ||
- | cout << " | ||
- | delete r4[0]; | ||
- | delete r4[1]; | ||
- | delete []r4; | ||
return 0; | return 0; | ||
- | } | + | } |
</ | </ | ||
- | Μεταγλωττίστε και εκτελέστε τον παραπάνω κώδικα. | + | Μεταγλωττίστε και εκτελέστε τον παραπάνω κώδικα. |
< | < | ||
Calling 0 args constructor | Calling 0 args constructor | ||
Calling 2 args constructor | Calling 2 args constructor | ||
+ | --- init r1 --- | ||
+ | --- init r2 --- | ||
Calling 0 args constructor | Calling 0 args constructor | ||
- | Calling 2 args constructor | ||
Calling 1 args constructor | Calling 1 args constructor | ||
+ | --- init r3 --- | ||
Calling 0 args constructor | Calling 0 args constructor | ||
Calling 2 args constructor | Calling 2 args constructor | ||
Calling 0 args constructor | Calling 0 args constructor | ||
- | Calling 2 args constructor | ||
Calling 1 args constructor | Calling 1 args constructor | ||
--------------- | --------------- | ||
- | Calling 0 args constructor | + | r' |
- | Calling 2 args constructor | + | |
- | Calling 1 args constructor | + | |
- | Calling 0 args constructor | + | |
- | Calling 2 args constructor | + | |
- | --------------- | + | |
- | rect' | + | |
*r1' | *r1' | ||
*r2' | *r2' | ||
r3[0]' | r3[0]' | ||
r3[1]' | r3[1]' | ||
- | r4[0]' | ||
- | r4[1]' | ||
--------------- | --------------- | ||
Destructing rectangle (w:2, h:2) | Destructing rectangle (w:2, h:2) | ||
Destructing rectangle (w:5, h:5) | Destructing rectangle (w:5, h:5) | ||
Destructing rectangle (w:3, h:4) | Destructing rectangle (w:3, h:4) | ||
- | --------------- | ||
- | Destructing rectangle (w:6, h:6) | ||
- | Destructing rectangle (w:2, h:6) | ||
Destructing rectangle (w:1, h:2) | Destructing rectangle (w:1, h:2) | ||
+ | </ | ||
+ | |||
+ | Παρατηρήστε ότι στον πίνακα //r3// πρώτα καταστρέφεται το αντικείμενο //r3[1]// και στη συνέχεια το αντικείμενο //r3[0]//. | ||
+ | ===== Ένα ακόμη πιο σύνθετο παράδειγμα αρχικοποίησης δεικτών ===== | ||
+ | |||
+ | Παρακάτω δίνεται η κλάση // | ||
+ | |||
+ | <code cpp RectangleUsage-2.cpp> | ||
+ | #include < | ||
+ | using namespace std; | ||
+ | #include " | ||
+ | |||
+ | /* Δημιουργώ ένα δυναμικά δεσμευμένο | ||
+ | * διδιάστατο πίνακα από αντικείμενα | ||
+ | * τύπου Rectangle. | ||
+ | */ | ||
+ | |||
+ | int main() { | ||
+ | | ||
+ | Rectangle **r4; | ||
+ | cout << "--- init r4 ---" << endl; | ||
+ | r4 = new Rectangle*[2]; | ||
+ | cout << "--- init r4[0] ---" << endl; | ||
+ | r4[0] = new Rectangle[2] {{5,6}, {7,8}}; | ||
+ | cout << "--- init r4[1] ---" << endl; | ||
+ | r4[1] = new Rectangle[3] {{9}, {10}, {11,10}}; | ||
+ | | ||
+ | cout << " | ||
+ | cout << " | ||
+ | cout << " | ||
+ | cout << " | ||
+ | cout << " | ||
+ | cout << " | ||
+ | cout << " | ||
+ | | ||
+ | delete[] r4[0]; | ||
+ | delete[] r4[1]; | ||
+ | delete[] r4; | ||
+ | } | ||
</ | </ | ||
cpp/object_lifecycle.txt · Last modified: 2021/05/07 06:35 (external edit)