Reputation: 251
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
class items{
char * name;
public:
items(const char * str){
int len = strlen(str);
this->name = new char [len];
strcpy(this->name,str);
cout << "Default ctor " << this->name << " \t@" << (this) << endl;
}
items(const items& obj){
int len = strlen(obj.name);
this->name = new char [len];
strcpy(name,obj.name);
cout << "Copy ctor " << this->name << " \t@" << this << endl;
}
~items(){
cout << "dtor \t" << this->name << "\t@" << this << endl;
delete [] name;
}
const char * getName() const{
return this->name;
}
};
ostream& operator<<(ostream& stream, const items& obj){
stream << obj.getName();
return stream;
}
int main(int argc, char ** argv){
items Ruler("Ruler"), Pencil("Pencil"), Book("Book"), Notebook("Notebook"), Sharpener("Sharpener");
vector<items> school;
school.push_back(Ruler);
school.push_back(Pencil);
school.push_back(Book);
return 0;
}
i have bizarre results. Can you explain what is happening behind the scene? Results:
Default ctor Ruler @0x62ff1c
Default ctor Pencil @0x62ff18
Default ctor Book @0x62ff14
Default ctor Notebook @0x62ff10
Default ctor Sharpener @0x62ff0c
Copy ctor Ruler @0x9cd1d0
Copy ctor Pencil @0x9cd504
Copy ctor Ruler @0x9cd500
dtor Ruler @0x9cd1d0
Copy ctor Book @0x9c0510
Copy ctor Ruler @0x9c0508
Copy ctor Pencil @0x9c050c
dtor Ruler @0x9cd500
dtor Pencil @0x9cd504
dtor Ruler @0x9c0508
dtor Pencil @0x9c050c
dtor Book @0x9c0510
dtor Sharpener @0x62ff0c
dtor Notebook @0x62ff10
dtor Book @0x62ff14
dtor Pencil @0x62ff18
dtor Ruler @0x62ff1c
What is happening after default constructions? why does this ruler create too many copies and destroy them? What is the problem here?
Upvotes: 0
Views: 120
Reputation: 481
Basically what is happening is that if a vector is full and you are pushing an element, the vector needs to resize. So when you push Ruler
on the vector there's an array with a size of sizeof(items)
created and the data is copied in(first copy constructor call for Ruler
). Then you are pushing Pencil
on the vector(first copy constructor call for Pencil
), but the vector is out of memory, so a new array is allocated with double of the previous size 2 * sizeof(items)
and the old array is copied to the new array(second copy constructor call for Ruler
) and the old array is destroyed(first destructor called for Ruler
in old array) and so on...
Upvotes: 1
Reputation: 153840
Your "default constructor" takes an argument and is, thus, not a default constructor in the C++ sense: default constructors can be called without any argument.
With respect to your question it seem the sequence is thus:
Ruler
object inserting it into the school
vector.Pencil
is inserted this object is first copied but apparently there isn't enough space in the school
vector: the Pencil
object is copied into a newly allocated location and then Ruler
is copied over and the original space is destroyed.Book
is inserted the same sequence happens: the Book
is copied into a new location and then Ruler
and Pencil
are copied there, too.The sequence is somewhat confusing in the sense that std::vector
normally doesn't behave like that: it normally creates a small array right at the start which can accomodate more than one element. It seems, the implementation used starts off with a capacity()
of just one and then doubles the capacity from there. You can verify this behavior by looking at school.capacity()
between the calls to school.push_back()
: whenever the capacity()
increases, the underlying array gets increased.
Considering that your are allocating memory you may want to consider a move constructor which transfers the stored memory rather than allocating a new array to accomodate a copy to then just delete
the original. The move constructor would look something like this:
items::items(items&& other)
: name(other.name) {
this->name = nullptr;
}
Upvotes: 2
Reputation: 89
std::vector manages its own memory. That means that std::vector only stores copies of an object, which means the object must have a meaningful copy constructor (and an assignment operator, but that's another issue).
When the destructor of a vector is invoked the memory held by the vector is released. std::vector also invokes an object's destructor when it is removed (through erase, pop_back, clear or the vector's destructor).
Upvotes: 1