#include <iostream>
#include <vector>
using namespace std;
class base
{
int x;
public:
base(int k){x =k; }
void display()
{
cout<<x<<endl;
}
base(const base&)
{
cout<<"base copy constructor:"<<endl;
}
};
int main()
{
vector<base> v;
base obase[5]={4,14,19,24,29};
for(int i=0; i<5; i++)
{
v.push_back(obase[i]);
}
}
When data is inserted into vector, copy to that data goes to vector using the copy constructor.
When i run this program,
for the first insertion (i=0), one time copy constructor is called.
for the second insertion (i=1), two times copy constructor is called
for the third insertion (i=3), three times copy constructor is called
for the fourth insertion (i=3), four times copy constructor is called
for the fifth insertion (i=4), five times copy constructor is called
Please any one can tell me why this is happening? For each insertion, shouldn't the copy constructor be called only once?
calls to push_back() increase the size of the vector as necessary, which involves copying of vector's contents. Since you already know that it's going to contain five elements, either v.reserve(5); right before the loop, or use the range constructor:
base obase[5]={4,14,19,24,29};
vector<base> v(obase, obase+5);
Your copy constructor is flawed, you forgot to actually copy the data :)
base(const base& that) : x(that.x)
{
cout << "base copy constructor\n";
}
Also, if you have a modern compiler, you can write a move constructor and learn something new:
base(base&& that) : x(that.x)
{
cout << "base move constructor\n";
}
If v needs to resize its internal buffer, it will usually allocate a totally fresh memory area, so it needs to copy all the objects that were previously in the vector to the new location. This is done using regular copying, so the copy constructor is invoked.
You should call reserve() on the vector to reserve storage upfront if you can estimate how many elements you are going to need.
Note that the resize/growth behaviour of std::vector is implementation-dependent, so your code sample will produce different results with different standard library implementations.
Related
I've been testing some C++11 features from some some.
I came across r-value references and move constructors.
I implemented my first move constructor, here it is:
#include <iostream>
#include <vector>
using namespace std;
class TestClass{
public:
TestClass(int s):
size(s), arr(new int[s]){
}
~TestClass(){
if (arr)
delete arr;
}
// copy constructor
TestClass(const TestClass& other):
size(other.size), arr(new int[other.size]){
std::copy(other.arr, other.arr + other.size, arr);
}
// move constructor
TestClass(TestClass&& other){
arr=other.arr;
size=other.size;
other.arr=nullptr;
other.size=0;
}
private:
int size;
int * arr;
};
int main(){
vector<TestClass> vec;
clock_t start=clock();
for(int i=0;i<500000;i++){
vec.push_back(TestClass(1000));
}
clock_t stop=clock();
cout<<stop-start<<endl;
return 0;
}
The code works fine. Anyway putting a std::cout inside the copy constructor i noticed that it gets called! And a lot of times.. (move constructor 500000 times, copy constructor 524287 times).
What surprised me more is that if i comment out the copy constructor from the code, the whole program gets a lot faster, and this time the move constructor is called 1024287 times.
Any clue?
Put noexcept on your move constructor:
TestClass(TestClass&& other) noexcept {
Elaboration: I was going to give this one Pierre, but unfortunately the cppreference source is only approximately correct.
In C++03
vector<T>::push_back(T)
has the "strong exception guarantee". That means that if the push_back throws an exception, the vector is left in the same state it had prior to the call to push_back.
This guarantee is problematic if the move constructor throws an exception.
When the vector reallocates, it would like to move the elements from the old buffer to the new. However if any one of those moves throws an exception (besides the first), then it is left in a state where the old buffer has been modified, and the new buffer doesn't yet contain everything it is supposed to. The vector can't restore the old buffer to its original state because it would have to move elements back to do so, those moves might also fail.
So a rule was laid down for C++11:
If T has a noexcept move constructor, that can be used to move the elements from the old buffer to the new.
Otherwise if T has a copy constructor, that will be used instead.
Otherwise (if there is no accessible copy constructor), then the move constructor will be used after all, however in this case, the strong exception safety guarantee is no longer given.
Clarification: "copy constructor" in rule 2 means a constructor taking a const T&, not one of those weenie so-called T& copy constructors. :-)
Use noexcept on your move constructor :
TestClass(TestClass&& other) noexcept { ... }
noexcept without a constant expression like this is equivalent to noexcept(true).
The compiler can use this information to enable certain optimizations on non-throwing functions as well as enable the noexcept operator, which can check at compile time if a particular expression is declared to throw any exceptions.
For example, containers such as std::vector will move their elements if the elements' move constructor is noexcept, and copy otherwise.
Source : http://en.cppreference.com/w/cpp/language/noexcept_spec
NB : This is a C++11 feature. Certain compiler may not have implemented it yet... (ex: Visual Studio 2012)
Copy constructor is called when all reserved memory inside std::vector is used. It is necessary to call std::vector::reserve() method before adding the elements.
vector<TestClass> vec;
vec.reserve(500000);
I tried to make my custom Vector class, with a template class.
I expect I can put my Vector<int> into a Vector<Vector<int>> variable. At least that was what I was hoping for... but it keeps crashing at the destructor code.
Here's my code.
#include <iostream>
#include <string>
template <typename T>
class Vector {
T* data;
int capacity;
int length;
public:
typedef T value_type;
Vector() {}
Vector(int n) : data(new T[n]), capacity(n), length(0) {}
void push_back(T input) {
data[length++] = input;
}
T operator[](int i) { return data[i]; }
virtual ~Vector() { if (data) delete[] data; }
};
int main() {
Vector<Vector<int>> v(3);
Vector<int> vv(4);
v.push_back(vv);
}
So I thought, maybe I should use a copy constructor, since it seems the problem is that v is being deleted before vv. Well, if I just comment out the destructor code, it will work, but that doesn't seem right to me...
So I made a custom copy constructor like this:
Vector(const T& other) {
}
But it give me an error, saying "ambiguous overloading"... looking back, of course it is wrong, since T of data is different from T of other...
How can I make my custom Vector class work? (i.e. I want push_back work as I intended...)
The general issue
In class design, especially when memory/resource allocation is involved, you typically need to follow the "Rule of Five" (which used to be the "Rule of Three" before C++11):
If you implement any of:
A destructor
An copy/move assignment operator
A copy/move constructor
then you will probably need to implement all of them.
The reason is that each of them likely needs to have some resource management logic, beyond what the language gives you as a default.
The signatures of these five methods, for your class, would be:
Method
Signature
Copy constructor
Vector(const Vector&)
Move constructor
Vector(Vector&&)
Copy assignment operator
Vector& operator=(const Vector&)
Move assignment operator
Vector& operator=(Vector&&)
Destructor
~Vector() or virtual ~Vector()
Your specific class
In your specific case, there are several concrete problems:
As #UnholySheep suggests, you mis-declared the copy constructor.
You implemented a default constructor; but - it doesn't allocate anything, nor does it initialize anything! The data pointer holds arbitrary junk, and when you try to free it, bad things are likely to happen.
You are performing quite a lot of copying of T values, which for the outer vector would be Vector<int> values - and that can get expensive.
Even if you fixed the above, you should still implement the missing methods from the "rule of five".
Your default constructor leaves the object completely uninitialized.
Consider what happens when you declare a
Vector<int> foo;
foo essentially gets a random memory address as data, a random length and capacity. This will give fireworks if you free it.
Perhaps you sidestepped this issue by always creating your vector with a predefined size. Luckily, trying to create/destroy a Vector<Vector<int>> brings this to light, because the Vector<int>[] inside your container still contains these ticking timebombs.
I wrote the following code to understand the move sementics of std::vector
class PointerHolder
{
public:
PointerHolder()
{
cout << "Constructor called" << endl;
}
//copy constructor
PointerHolder(const PointerHolder& rhs)
{
cout << "Copy Constructor called" << endl;
}
//copy assignment operator
PointerHolder& operator = (const PointerHolder& rhs)
{
cout << "Copy Assignment Operator called" << endl;
return *this;
}
// move constructor
PointerHolder(PointerHolder&& rhs)
{
cout << "Move Constructor called" << endl;
}
// move assignment operator
PointerHolder& operator = (PointerHolder&& rhs)
{
cout << "Move Assignment Operator called" << endl;
return *this;
}
};
void processVector(std::vector<PointerHolder> vec)
{
}
int main()
{
vector<PointerHolder> vec;
PointerHolder p1;
PointerHolder p2;
vec.push_back(p1);
vec.push_back(p2);
cout << "Calling processVector\n\n" << endl;
processVector(std::move(vec));
}
Since I pass an Rvalue reference of the vector When calling processVecor, what Actually should get called is the move constructor of the std::vector when the function parameter object is formed. Is that right ?
So I expected the move constructor of the vecor within itself woud call the move constructor of the PointerHolder class.
But there was no evidence printed to confirm that.
Can you please clarify the behaviour. Doesn't the move constructor of the std::vector in turn call the move constructor of the individual items
No. Note that the complexity requirement of move contructor of std::vector is constant.
Complexity
6) Constant.
That means the move contructor of std::vector won't perform move operation on every individual elements, which will make the complexity to be linear (like copy constructor). The implementation could move the inner storage directly to achieve it.
No. It pilfers the entire block of memory with all the elements instead. Why bother moving the contents when you can just grab the whole thing?
(The allocator-extended move constructor will need to perform a memberwise move if the supplied allocator compares unequal to the source vector's allocator.)
No, it doesn't require the elements to be moved when calling the move constructor of the std::vector. To understand why, I think you should have a good mental model of how std::vector is implemented. (Most implementations look like this, except they need some more complexity for dealing with allocators)
So what is std::vector?
In the simplest form, it has 3 members:
A capacity: (size_t)
A size: (size_t)
A pointer to data (T*, std_unique_ptr, void*)
The size indicates how many elements in use, the capacity indicates how much data fits in the currently allocated data. Only when your new size would become larger than the capacity, the data needs to be reallocated.
The data that is allocated is uninitialized memory, in which in-place the elements get constructed.
So, given this, implementing the move of a vector would be:
Copy over capacity/size
Copy over the pointer and set to nullptr in original (same behavior as unique_ptr)
With this, the new instance is completely valid. The old one is in a valid but unspecified state. This last one means: you can call the destructor without crashing the program.
For vector, you can also call clear to bring it back to a valid state, or the operator=.
Given this model, you can easily explain all operators. Only move-assignment is a bit more complex.
No. It doesn't call the move constructor. To call move constructor of element you will have to call std::move while pushing to vector itself.
int main()
{
vector<PointerHolder> vec;
PointerHolder p1;
PointerHolder p2;
vec.push_back(std::move(p1));
vec.push_back(p2);
cout << "Calling processVector\n\n" << endl;
processVector(std::move(vec));
}
output
Constructor called
Constructor called
Move Constructor called
Copy Constructor called
Calling processVector
If we're looking at the standard (https://en.cppreference.com/w/cpp/container/vector/vector), it says, moving requires constant amount of time O(1).
Regardless of that, if we're looking at most common implementations, std::vector is a dynamic array. A dynamic array first allocates for example space for 8 elements. If we need space for 9 that this 8 is multiplied or increased by a specific amount, often multiplied bei 1.44, 2 or sth. like that.
But as concerns the moving aspect: what are our member variables and how do we move them? Well, the dynamic array is just - as mentioned - a pointer to the first element and if we wanna move the structure we'll copy the pointer to the other object and set the old pointer to nullptr (or NULL if you don't care for the issue for what nullptr has been implemented for, nullptr is obviously preferrable). And of course things like internal saved size (if saved) has to be copied and in the old object has to be set to zero as well (or whatever move semantics are there).
I have this below program, where I am passing a vector by reference to a function myFunc and inside this function, I am adding few elements to the vector.
I am not freeing object creating with new, for now ignore the memory leak due to this.
After myFunc() execution is complete I am printing the variables ctor and dtor
to know how many times constructor and destructor were called.
Output is:
Before Exiting 5 7
I am creating 5 objects so ctor is 5. But why is dtor 7? From where do the extra two counts? Am I missing something?
#include
#include
using namespace std;
static int ctor = 0;
static int dtor = 0;
class MyClass
{
public:
MyClass(int n)
{
i = n;
ctor++;
// cout << "Myclass ctor " << ctor << endl;
}
~MyClass()
{
dtor++;
// cout << "Myclass dtor" << dtor << endl;
}
private:
int i;
};
void myFunc(vector<MyClass> &m);
void myFunc(vector<MyClass> &m)
{
MyClass *mc;
for(int i = 0; i < 5; i++)
{
mc = new MyClass(i);
m.push_back(*mc);
}
}
int main()
{
vector<MyClass> m;
vector<MyClass>::iterator it;
myFunc(m);
cout << "Before Exiting " << ctor << " " << dtor << endl;
}
Vectors copy around objects, but only your int constructor increments ctor. That's not accounting for copy constructed objects, and because you didn't provide one, the compiler provided it for you.
Add
MyClass(const MyClass& rhs) i(rhs.i) { ++ctor; }
to your class to see if that balances the count.
Vectors start at a low size. When you push an element into them, they make a copy of it using the copy constructor so you don't see your normal constructor get called. When the vector size grows beyond its limit, it will increase its limit by a multiple of its current size (e.g. double it).
Vectors are guaranteed to always keep objects in contiguous memory, so if adding a new object exceeds the vectors capacity() (i.e. size() + 1 > capacity()), the vector allocates new memory somewhere and copies all elements into it. This will again use the copy constructor. So, your elements from the vector pre-resize will call their destructors after they are copied into the newly allocated space with their copy-constructor.
So, more destructor calls than normal constructor calls :)
Vectors sometimes call another constructor, copy constructor, which was implicitly generated by the compiler for your class. That's why some ctor++ calls are missing: not all objects were constructed with the constructor you defined, some were constructed with the other one.
To ensure correct behavior of a type (class) with vector, you must implement copy constructor for it:
MyClass(const MyClass& rhs) { i = rhs.i; ++ctor; } // copy constructor
...because the one generated by compiler does nothing.
As indicated by others, the reason behind your result is the copy constructor and resizing of the vector. A vector has both a size and a capacity. The capacity is normally always doubled when the vector has to resize to accommodate new elements so that resizing does not have to happen all that often.
Adding some trace code to print out the vector capacity between each push_back gives more clarity into this behaviour.
m.capacity(): 0
m.capacity(): 1
m.capacity(): 2
m.capacity(): 4
m.capacity(): 4
m.capacity(): 8
Before Exiting 5 7
What actually happens here is that the only time the destructor is called is when the vector is resized (see why below). The first time it's resized it has no elements, thus the destructor is never called. The second time, the capacity is 1 so the destructor is called once. The third time it's called twice and the fourth time it's called four times. This totals seven times called, just as the counter shows.
The elements dynamically allocated in myFunc are never deallocated, so the destructor never runs there, and the final printout ("Before Exiting...") is done before leaving the scope in which the vector is allocated, so the destructor for the last "vector reincarnation" isn't called until after that printout. Therefore, the destructor of MyClass is only called when the vector is resized.
ยง 12.8.8 of the C++ standard says: If the class definition does not explicitly declare a copy constructor, there is no user-declared move constructor, and there is no user-declared move assignment operator, a copy constructor is implicitly declared as defaulted (8.4.2). Such an implicit declaration is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.
Basically, since your struct violates the rule of five, the compiler made a copy constructor and assignment operator for you. That other constructor doesn't increment ctor, but uses the destructor you defined. The vector is then using that alternate constructor, as a speed improvement.
If you add protected: MyClass(const MyClass& b); to the class declaration, this problem goes away.
How do you copy your STL containers?
// big containers of POD
container_type<pod_type> source;
container_type<pod_type> destination
// case 1
destination = source;
// case 2
destination.assign(source.begin(), source.end());
// case 3 assumes that destination.size() >= source.size()
copy(source.begin(), source.end(), destination.size());
I use case 1 whenever possible. Case 2 is for containers of different types. Case 3 is needed when the destination is larger than the source and you want to keep the remaining elements.
But how about non-POD elements with non-zero construction/destruction cost? Can case 3 be better than case 2? If the destination is larger than the source, the implementation can do rather unexpected things. This is what Visual Studio 2008 does in case 2.
All elements of the destination are destroyed.
Then the copy constructor is called as many times as the destination's size. Why?
All elements of the source are assigned to the corresponding elements of the destination.
The extra elements of the destination are destroyed.
GCC 4.5 does it better. All elements of the source are copied via assignment and then the extra elements of the destination are destroyed. Using case 3 followed by resize does the same thing on both platforms (except one default constructor which resize needs). Here is the toy program which shows what I mean.
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
struct A {
A() { cout << "A()\n"; }
A(const A&) { cout << "A(const A&)\n"; }
A& operator=(const A&) {
cout << "operator=\n";
return *this;
}
~A() { cout << "~A()\n"; }
};
int main() {
list<A> source(2);
vector<A> desrination1(3);
vector<A> desrination2(3);
cout << "Use assign method\n";
desrination1.assign(source.begin(), source.end());
cout << "Use copy algorithm\n";
copy(source.begin(), source.end(), desrination2.begin());
desrination2.resize(2);
cout << "The End" << endl;
return 0;
}
All elements of the destination are
destroyed. Then the copy constructor
is called as many times as the
destination's size. Why?
Not sure what you are talking about. assign is usually implemented something as:
template<class Iterator>
void assign(Iterator first, Iterator last)
{
erase(begin(), end()); // Calls the destructor for each item
insert(begin(), first, last); // Will not call destructor since it should use placemenet new
}
with copy you would do something like:
assert(source.size() <= destination.size());
destination.erase(copy(source.begin(), source.end(), destination.begin()), destination.end());
Which should be pretty much the same thing. I would use copy if i knew for sure that the source will fit into the destination (a bit faster since assign/insert needs to check the capacity of the container) otherwise i would use assign since it's simplest. Also if you use copy and the destination is too small, calling resize() is inefficient since resize() will construct all elements which will be overwritten eitherway.
GCC 4.5 does it better. All elements
of the source are copied via
assignment and then the extra elements
of the destination are destroyed.
Using case 3 followed by resize does
the same thing on both platforms
(except one default constructor which
resize needs). Here is the toy program
which shows what I mean.
It's the same thing. Assignment is implemented in terms of copy construction.
class A
{
A& operator=(A other)
{
std::swap(*this, other);
return *this;
}
// Same thing but a bit more clear
A& operator=(const A& other)
{
A temp(other); // copy assignment
std::swap(*this, temp);
return *this;
}
}
If you copy a whole container, you should rely on the container copy constructor or assignment operator. But if you copy only the container content from one to another, the best is to use std::copy.
You can't save the copy constructor call for each instance if you use more than a POD object.
You should consider using shared/smart pointers which will only increment their reference counters on copying and use copy on write when you modify your instance.