User Tools

Site Tools


cpp:copy_constructors

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
cpp:copy_constructors [2021/05/07 08:03] – [Μια πιο σύνθετη περίπτωση] gthanoscpp:copy_constructors [2022/05/12 19:41] (current) – [Πιο σύνθετες περιπτώσεις] gthanos
Line 23: Line 23:
     int getHeight();     int getHeight();
 }; };
 +</code>
 +
 +<code cpp Rectangle.cpp>
 +#include "Rectangle.hpp"
  
 Rectangle::Rectangle(int w, int h) { Rectangle::Rectangle(int w, int h) {
Line 29: Line 33:
 } }
  
-Rectangle::Rectangle(int s) {+Rectangle::Rectangle(int s) {
   cout << "Calling 1 args constructor" << endl;   cout << "Calling 1 args constructor" << endl;
   width = s; height = s;   width = s; height = s;
Line 64: Line 68:
 {{ :cpp:cppstackcopyconstructor.png |}} {{ :cpp:cppstackcopyconstructor.png |}}
  
-Το ερώτημα είναι με ποιό τρόπο γίνεται η δημιουργία του αντιγράφου του αρχικού αντικειμένου στο //stack//. Μπορείτε να δηλώσετε τον δικό σας κατασκευαστή αντιγραφέα (λεπτομέρειες πιο κάτω..) ή να αφήσετε τον //compiler// να δηλώσει τον //default//. Ο //default// κατασκευαστής αντιγραφέας δημιουργεί το νέο αντικείμενο από το παλιό αντιγράφοντας τα πεδία πεδίο προς πεδιο. Εάν αυτός ο τρόπος σας ικανοποιεί, τότε δεν χρειάζεται να κάνετε κάτι περισσότερο. Εάν όμως η παραπάνω μεθοδολογία δεν είναι ικανοποιητική, είστε αναγκασμένοι να ορίσετε τον δικό σας κατασκευαστή αντιγραφέα.+Το ερώτημα είναι με ποιό τρόπο γίνεται η δημιουργία του αντιγράφου του αρχικού αντικειμένου στο //stack//. Μπορείτε να δηλώσετε τον δικό σας κατασκευαστή αντιγραφέα (λεπτομέρειες πιο κάτω..) ή να αφήσετε τον //compiler// να δηλώσει τον //default//. Ο //default// κατασκευαστής αντιγραφέας δημιουργεί το νέο αντικείμενο από το παλιό αντιγράφοντας τα πεδία ένα προς ένα. Εάν αυτός ο τρόπος σας ικανοποιεί, τότε δεν χρειάζεται να κάνετε κάτι περισσότερο. Εάν όμως η παραπάνω μεθοδολογία δεν είναι ικανοποιητική, είστε αναγκασμένοι να ορίσετε τον δικό σας κατασκευαστή αντιγραφέα.
  
 ===== Ορισμός ενός κατασκευαστή αντιγραφέα ===== ===== Ορισμός ενός κατασκευαστή αντιγραφέα =====
Line 99: Line 103:
     Rectangle(int s);     Rectangle(int s);
     Rectangle();     Rectangle();
-    Rectangle(Rectangle& r);+    Rectangle(const Rectangle& r);
     void setWidth(int w);     void setWidth(int w);
     void setHeight(int h);     void setHeight(int h);
Line 105: Line 109:
     int getHeight();     int getHeight();
 }; };
 +</code>
 +
 +<code cpp Rectangle.cpp>
 +#include "Rectangle.hpp"
  
 Rectangle::Rectangle(int w, int h) { Rectangle::Rectangle(int w, int h) {
Line 168: Line 176:
 </WRAP> </WRAP>
  
-===== Μια πιο σύνθετη περίπτωση =====+===== Πιο σύνθετες περιπτώσεις ===== 
 + 
 +==== 1η Περίπτωση - Αρχικοποίηση ενός αντικειμένου με δυναμικά δεσμευμένα πεδία από άλλο αντικείμενο ====
  
 Στις περιπτώσεις που υπάρχουν πεδία που είναι δείκτες και δείχνουν σε άλλα αντικείμενα (στατικά ή δυναμικά δεσμευμένα) εάν δεν ορίσετε τον δικό σας κατασκευαστή αντιγραφέα, ο //default// αντιγράφει τις διευθύνσεις αυτές πεδίο προς πεδίο, όπως θα αντιγράφονταν οποιοδήποτε άλλο πεδίο. Αυτό πρακτικά σημαίνει ότι δύο ή περισσότερα αντικείμενα δείχνουν σε μία κοινή περιοχή μνήμης μέσω των αντίστοιχων πεδίων τους. Το παραπάνω μπορεί να προκαλέσει δυσλειτουργίες, καθώς η μεταβολή του περιεχομένου της κοινής μνήμης επηρεάζει το σύνολο των αντικειμένων που το μοιράζονται. Ενδεικτικό είναι το παρακάτω παράδειγμα. Στις περιπτώσεις που υπάρχουν πεδία που είναι δείκτες και δείχνουν σε άλλα αντικείμενα (στατικά ή δυναμικά δεσμευμένα) εάν δεν ορίσετε τον δικό σας κατασκευαστή αντιγραφέα, ο //default// αντιγράφει τις διευθύνσεις αυτές πεδίο προς πεδίο, όπως θα αντιγράφονταν οποιοδήποτε άλλο πεδίο. Αυτό πρακτικά σημαίνει ότι δύο ή περισσότερα αντικείμενα δείχνουν σε μία κοινή περιοχή μνήμης μέσω των αντίστοιχων πεδίων τους. Το παραπάνω μπορεί να προκαλέσει δυσλειτουργίες, καθώς η μεταβολή του περιεχομένου της κοινής μνήμης επηρεάζει το σύνολο των αντικειμένων που το μοιράζονται. Ενδεικτικό είναι το παρακάτω παράδειγμα.
Line 200: Line 210:
     void setX(int vx) { x = vx; }     void setX(int vx) { x = vx; }
     void setY(int vy) { y = vy; }     void setY(int vy) { y = vy; }
-    int getX() { return x; } +    int getX() const { return x; } 
-    int getY() { return y; }+    int getY() const { return y; }
 }; };
 </code> </code>
Line 229: Line 239:
     int getHeight();     int getHeight();
     void setOrigin(Point *p);     void setOrigin(Point *p);
-    Point *getOrigin();+    Point *getOrigin() const;
 }; };
 +</code>
 +
 +<code cpp Rectangle.cpp>
 +#include "Rectangle.hpp"
  
 Rectangle::Rectangle(int w, int h, Point p) { Rectangle::Rectangle(int w, int h, Point p) {
Line 259: Line 273:
 int Rectangle::getHeight() { return height; } int Rectangle::getHeight() { return height; }
 void Rectangle::setOrigin(Point *p) { origin = p; } void Rectangle::setOrigin(Point *p) { origin = p; }
-Point *Rectangle::getOrigin() { return origin; }+Point *Rectangle::getOrigin() const { return origin; }
 </code> </code>
  
-<code cpp MoveOrigin.cpp>+<code cpp CopyRectangle.cpp>
 #include "Rectangle.hpp" #include "Rectangle.hpp"
- 
-int moveOrigin(Rectangle &r, int dx, int dy) { 
-  Point *p = r.getOrigin(); 
-  p->setX(p->getX() + dx); 
-  p->setY(p->getY() + dy); 
-} 
  
 int main() { int main() {
Line 275: Line 283:
   Rectangle r1{5,6,p};     Rectangle r1{5,6,p};  
   Rectangle r2 = r1;   Rectangle r2 = r1;
-  Rectangle r3(r1); 
-   
-  moveOrigin(r1, 1,-1); 
 } }
 </code> </code>
Line 286: Line 291:
  
 <code> <code>
-*** Error in `./a.out': double free or corruption (fasttop): 0x00000000006d6010 *** +free(): double free detected in tcache 2 
-Ακυρώθηκε (core dumped)+Aborted (core dumped)
 </code> </code>
  
Line 296: Line 301:
 Ο προτεινόμενος κατασκευαστής αντιγραφέας δίνεται παρακάτω: Ο προτεινόμενος κατασκευαστής αντιγραφέας δίνεται παρακάτω:
 <code cpp> <code cpp>
-Rectangle::Rectangle(Rectangle &r) {+Rectangle::Rectangle(const Rectangle &r) {
   width = r.width;   width = r.width;
   height = r.height;   height = r.height;
Line 311: Line 316:
 </code>  </code> 
  
 +==== 2η Περίπτωση - Κλήση συνάρτησης με παράμετρο αντικείμενο που περιέχει δυναμικά δεσμευμένα πεδία ====
 +
 +<code cpp MoveOrigin.cpp>
 +#include "Rectangle.hpp"
 +
 +int moveOrigin(Rectangle r, int dx, int dy) {
 +  Point *p = r.getOrigin();
 +  p->setX(p->getX() + dx);
 +  p->setY(p->getY() + dy);
 +}
 +
 +int main() {
 +  Point p{5,5};
 +  Rectangle r1{5,6,p};  
 +  
 +  moveOrigin(r1, 1,-1);
 +}
 +</code>
 +
 +Η κλήση της συνάρτησης moveOrigin θα απαιτήσει τη δημιουργία ενός αντιγράφου του r1 στο stack για τις ανάγκες της εκτέλεσης της συγκεκριμένης συνάρτησης. Εφόσον δεν έχουμε δημιουργήσει κατασκευαστή αντιγραφέα, τα πεδία του r1 θα αντιγραφούν ένα προς ένα στην τοπική μεταβληή r. Αυτό θα έχει ως συνέπεια το πεδίο origin των αντίκειμένων r εντός της συνάρτησης moveOrigin και r1 της main να δείχνουν σε μία κοινή περιοχή δυναμικά δεσμευμένης μνήμης.
 +
 +Κατά την έξοδο από τη συνάρτηση η κοινή αυτή περιοχή θα καταστραφεί, έτσι ώστε το αντικείμενο r1 στη main να δείχνει σε μία περιοχή που έχει ήδη αποδεσμευτεί. Η έξοδος από τη main θα σηματοδοτήσει την καταστροφή του r1 μέσω του καταστροφέα της κλάσης. Όταν ο καταστροφέας θα επιχειρήσει να αποδεσμεύσει μνήμη που έχει ήδη αποδεσμευτεί θα λάβετε ένα μήνυμα λάθους όμοιο με το μήνυμα της προηγούμενης περίπτωσης.
 +
 +<code>
 +free(): double free detected in tcache 2
 +Aborted (core dumped)
 +</code>
 +
 +Η δημιουργία του κατασκευαστή αντιγραφέα που προτάθηκε παραπάνω λύνει και αυτό το πρόβλημα.
cpp/copy_constructors.1620374609.txt.gz · Last modified: 2021/05/07 07:03 (external edit)