Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std c++ container element destruction and insertion behaviour

I have made the following little Program: (basically a class that couts if it gets created, copied or destroyed and a main that does some of that)

class Foo
{
public:
 Foo(string name): _name(name)
 {
  cout << "Instance " << _name << " of Foo created!" << std::endl;
 };
 Foo(const Foo& other): _name(other._name)
 {
  cout << "Instance " << _name << " of Foo copied!" << std::endl;
 };

 ~Foo()
 {
  cout << "Instance " << _name << " of Foo destroyed!" << std::endl;
 }
 string _name;
};



int main( int argc, char**argv)
{
 Foo albert("Albert");
 Foo bert("Bert");
 {
  vector<Foo> v1, v2;
  system("PAUSE");  

  v1.push_back(albert);
  system("PAUSE");

  v2.push_back(bert);
  system("PAUSE");

  v1 = v2;
  system("PAUSE");  
 }
  system("PAUSE");
}

The output looks like this:

Instance Albert of class Foo created!
Instance Bert of class Foo created!
Press any key...
Instance Albert of class Foo copied!    
Instance Albert of class Foo copied!     // why another copy?
Instance Albert of class Foo destroyed!  // and destruction?
Press any key...
Instance Bert of class Foo copied!
Instance Bert of class Foo copied!
Instance Bert of class Foo destroyed!
Press any key...                      // v1=v2 why did the albert instance not get destroyed?
Press any key...                       
Instance Bert of class A destroyed!
Instance Bert of class A destroyed!
Press any key...                       // there's still an albert living in the void

This strikes me as very odd. Why do I even bother passing something as a reference if it gets copied twice anyway? Why does the v1.operator=(other) not destroy the elements it contains? It would fit nicely with the behaviour of shared_ptr. Can someone tell me why?

ADDITION I put this in an endless loop and checked the mem usage, it doesn't seem to produce a mem leak at least.

ADDITION Ok, the mem is not an issue because it uses operator= rather than the copy ctor, ok thanks. When I add

v1.reserve(10);
v2.reserve(10);

the logical number of copies takes place. without that it reallocates and copies the whole vector for every single push_back, (which I find quite retarded even for small vectors). Looking at this I will consider using .reserve more and optimize my assignment operators Like hell :)

ADDITION: SUMMARY

  1. All these issues seem specific to VC++2005.
  2. If the size of the two containers match, my implementation uses operator= on the elements instead of destroying the old ones and copying the new ones, which seems sound practice. IF the sizes differ, normal destruction and copying are used.
  3. With the 2005 Implementation, one has to use reserve! Otherwise abysmal and not std compliant performance.
  4. These black boxes are much blacker than I thought.
like image 716
AndreasT Avatar asked Sep 07 '09 13:09

AndreasT


1 Answers

Why do I even bother passing something as a reference if it gets copied twice anyway?

You should consider STL container types as blackbox that can copy the objects you store as often as they need to. For instance, every time the container is resized, all of the objects will be copied.

It is possible that your compiler's implementation of push_back() uses a temporary extra copy. On my machine (gcc on Mac OS X), there are no extra copies during push_back() (according to your program's output).

This copy happens somewhere in the STL code, not in your copy constructor (since it uses a reference).

Why does the v1.operator=(other) not destroy the elements it contains?

Foo::operator= will be called for the "albert" instance with the "bert" instance as argument. Therefore, there is no implicit destroy and copy operation here. You might want to verify this by providing your own implementation for the operator:

Foo& operator=(const Foo& other) {
    cout << "Instance " << other._name << " of Foo assigned to " << _name << "!" << std::endl;
    return *this;
}

This produces the following output on my machine:

Instance Albert of Foo created!
Instance Bert of Foo created!
Instance Albert of Foo copied!
Instance Bert of Foo copied!
Instance Bert of Foo assigned to Albert!
Instance Bert of Foo destroyed!
Instance Albert of Foo destroyed!
Instance Bert of Foo destroyed!
Instance Albert of Foo destroyed!

like image 116
Ferdinand Beyer Avatar answered Nov 15 '22 10:11

Ferdinand Beyer