Tuesday, June 13, 2017

Copy constructor or assignment operator

Using default copy constructor or assignment operator may cause misleading behavior as following code I wrote.
  1 #include <iostream>
  2 #include <vector>
  3 
  4 class Bad {
  5     public:
  6 
  7     Bad(int v) {
  8         data = new std::vector<int>();
  9         data->push_back(v);
 10     }
 11 
 12     // No copy constructor. Using default.
 13 
 14     // No assignment operator. Using default.
 15 
 16     std::vector<int> *data;
 17 
 18     void add(int v) {
 19         data->push_back(v);
 20     }
 21 
 22     void show() {
 23         std::vector<int>::iterator it;
 24         for (it = data->begin(); it != data->end(); ++it) {
 25             std::cout << *it << " ";
 26         }
 27         std::cout << std::endl;
 28     }
 29 };
 30 
 31 class Good {
 32     public:
 33 
 34     Good(int v) {
 35         data = new std::vector<int>();
 36         data->push_back(v);
 37     }
 38 
 39     // Copy constructor.
 40     Good(const Good& rhs) {
 41 
 42         std::cout << "Copy constructor called" << std::endl;
 43 
 44         if (this == &rhs) {
 45             // Copy to self. No action required.
 46             return;
 47         }
 48 
 49         this->data = new std::vector<int>();
 50 
 51         // Copy elements in data manually!
 52         std::vector<int>::iterator it;
 53         for (it = rhs.data->begin(); it != rhs.data->end(); ++it) {
 54             this->data->push_back(*it);
 55         }
 56     }
 57 
 58     // Assignment operator.
 59     Good& operator=(const Good& rhs) {
 60         std::cout << "Assignment operator called" << std::endl;
 61 
 62         if (&rhs == this) {
 63             return *this;
 64         }
 65 
 66         // Copy elements in data manually!
 67         this->data->clear();
 68         std::vector<int>::iterator it;
 69         for (it = rhs.data->begin(); it != rhs.data->end(); ++it) {
 70             this->data->push_back(*it);
 71         }
 72 
 73         return *this;
 74     }
 75 
 76     std::vector<int> *data;
 77 
 78     void add(int v) {
 79         data->push_back(v);
 80     }
 81 
 82     void show() {
 83         std::vector<int>::iterator it;
 84         for (it = data->begin(); it != data->end(); ++it) {
 85             std::cout << *it << " ";
 86         }
 87         std::cout << std::endl;
 88     }
 89 };
 90 
 91 int main() {
 92 
 93     std::cout << "<<<< Testing Bad. >>>>" << std::endl;
 94 
 95     Bad b1 = Bad(10);
 96     Bad b2 = b1; // Calls copy constructor.
 97 
 98     b2.show(); // Prints 10 .
 99     b1.add(20);
100     b2.show(); // Prints 10 20 (!)
101 
102     std::cout << "<<<< Testing Good. >>>>" << std::endl;
103 
104     Good g1 = Good(10);
105     Good g2 = g1; // Calls copy constructor.
106 
107     g2.show(); // Prints 10 .
108     g1.add(20);
109     g2.show(); // Prints 10 . :)
110 
111     g2 = g1; // Calls assignment operator.
112     g2.show(); // Prints 10 20 . :)
113 }