Sunday, 27 May 2018

STL is all about copying

These days, C++ programmers don't have to write their own containers like list, stack, queue, string, dictionary, set, map etc. STL provides all these containers. Hence it is a great savior. otherwise one may spent half of its time debugging these data structure if she/he encounter crash or bug. since this library is reliable you can focus on your algorithm without worrying about data structure implementation. But still you have to understand how it works and use it carefully. Here we will talk about one item that you can take care of :

STL work on copying: 

STL works on principle of copying. It copies the data when u add data to it, delete data from it, get data from it, iterate over it. 

When it is about copying of built-in data types, it does not cost much but when it comes to user defined data type, copying means calling copy constructor function.
e.g. If I want to save integers in a list and print at the end, code will look like this. 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int main() {
  std::list<int> l;
  l.push_back(1);
  l.push_back(5);
  l.push_back(10);

//! do other stuff and finally print
  auto iter = l.begin(), iter_end = l.end;
  for(; iter != iter_end ; ++iter) {
    int value = *iter;
    cout<<value<<endl;
  }
}

This code will work perfectly fine. There is no issue in it.

but now let us save info of students in list.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class student {
  int roll_num;
  char *name;
  char *address;

public :  

//! constructor
//! destructor
//! copy constructor
  student(const student &rhs) {
   roll_num = rhs.roll_num;
   name = new char[strlen(rhs.name)+1];
   strcpy(name,rhs.name);
   address = new char[strlen(rhs.address)+1];
   strcpy(address,rhs.address);

 }
};

int main() {
   student s1(1,"abcdef","address1");
   student s2(2,"dwse","address2");
   student s3(3,"rrrr","address3");
   list<student> l;
   l.push_back(s1);
   l.push_back(s2);
   l.push_back(s3);
//! do other stuff and finally print
   auto it = l.begin(), it_end = l.end();
   for(; it != it_end ; ++it) {
     student s = *it;
     cout<<s.get_name()<<endl;
     cout<<s.get_roll_number()<<endl;
   }

}

This seems same as we wrote it for list of integers. But you can make this program work faster or in other words, this program works slower. How??

Answer is because of copying.  Now you will be wondering where did copy happen? I didn't copy anywhere.

let us start dry running this code.
  • at #22,#23 and #24 constructor of student class will be called. 
  • at #25 , list will be created.
  • at #26,#27 and #28 elements i.e. s1,s2 and s3 will be put into list by copying i.e. by calling copy constructor
  • at #30 , I am setting the iterators.
  • at #32, I am getting current element from the list which is returned by copying.
  • Next lines does the printing job.
Here I am making unnecessary copies of each student object twice but without knowing. This is very simple example where you might hardly notice any time glitch but imagine if there is some bigger class that has 100s or 1000s of complex data members and your list size is also in millions.  

Now we have identified the problem, what is its solution? 
You can't change working of STL. 

Answer is save pointers in STL containers instead of direct objects. 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class student {
  int roll_num;
  char *name;
  char *address;

public :  

//! constructor
//! destructor
//! copy constructor

  student(const student &rhs) {
   roll_num = rhs.roll_num;
   name = new char[strlen(rhs.name)+1];
   strcpy(name,rhs.name);
   address = new char[strlen(rhs.address)+1];
   strcpy(address,rhs.address);

 }
};

int main() {
   student *ps1 = new student(1,"abcdef","address1");
   student *ps2 = new student(2,"dwse","address2");
   student *ps3 = new student(3,"rrrr","address3");
   list<student*> l;
   l.push_back(ps1);
   l.push_back(ps2);
   l.push_back(ps3);
//! do other stuff and finally print
   auto it = l.begin(), it_end = l.end();
   for(; it != it_end ; ++it) {
     student *s = *it;
     cout<<s->get_name()<<endl;
     cout<<s->get_roll_number()<<endl;
   }

}

Here I am saving pointers in list and when element will be added or retrieved from list it will add/return you copy of pointer but not copy of object which is fine.

In nut shell, save pointers instead of object(of user defined data type) in STL containers. 

No comments:

Post a Comment

what is array

Array is one of the simplest and most  sophisticated data structures. In array data is stored at contiguous memory locations. E.g. say you h...