class B
{
private:
int _x;
public:
int get(){return _x;};
B(int x=10):_x(x){cout<<"Default constructor "<<endl;}
~B(){cout<<"destructor "<<endl;}
B(const B &rhs){cout<<"copy constructor"<<endl;}
B& operator =(const B &rhs){cout<<"copy assignment operator"<<endl;}
int operator *(){cout<<"operator *"<<endl;return _x;}
};
int main()
{
vector<B> v;
int i;
vector<B>::iterator ii=v.begin();
for(i=0;i<1;i++)
{
v.push_back(*(new B(i*100)));
}
ii = v.begin();
cout<<"#####################"<<endl;
ii = v.insert(ii+1,*(new B()));
cout<<"#####################"<<endl;
return 0;
}
Output:
Default constructor
copy constructor
#####################
Default constructor
1. copy constructor
2. copy constructor
destructor
#####################
destructor
destructor
Why is that at v.insert(ii,*(new B()));, two copy constructors are called ??
First of all you have memory leaks as you don't delete the memory allocated from new.The correct way of doing what you want to do is v.push_back(B(100));.
Regarding why the copy ctor is called twice,it looks like on second insert the vector has reached its capacity and is reallocating. During this reallocation it copies the previously inserted elements into the newly allocated memory. Hence you see the copy ctor being called twice.
A far worse problem is that *(new B()) is a memory leak - you copy a dynamically-allocated object, and then throw away the only pointer to it. You should create a temporary object instead:
v.insert(ii+1, B());
To answer the question: since vectors are stored as contiguous blocks of memory, it's sometimes necessary to increase the capacity as they grow. When this happens, all the objects in the array must be copied (or moved) to their new location. So here you see one copy to move the existing element, and a second to insert the new one.
Related
I have a Double free or corruption (fasttop) error on this code.
I think i missed something on the "copy constructor".
class Vector{
int taille;
int* ptr;
public:
Vector():taille(0), ptr(NULL){
...
}
Vector(int n){
...
}
//The most important one
Vector(const Vector& source){
if(source.ptr != NULL){
taille = source.taille;
ptr = new int[taille];
for(int i=0;i<taille;i++) ptr[i]=source.ptr[i];
}else{
taille=0;
ptr=NULL;
}
cout << "Copy constructor" << endl;
}
~Vector(){
if(ptr!=NULL) delete ptr;
}
};
And here's the test :
int main()
{
Vector b(5);
Vector a(b);
a=Vector(12);
return 0;
}
The above = operator does not call the copy constructor. Why ?
It says : "double free or corruption (fasttop)"
With the expression
a = Vector(12)
a few things are happening:
First a new temporary Vector object is created (from Vector(12)). This is constructed using the Vector(int) constructor.
The temporary object is assigned to a, using a.operator=(<temporary object>).
The default compiler-generated operator= function does a simple member-wise assignment, i.e. it basically does ptr = other.ptr. This means you now have two objects ptr members pointing to the same memory: The temporary object, and a.
The temporary object is destructed once the assignment is made. This means the memory occupied by that object is passed to delete (which really should be delete[]).
This of course means that a.ptr is no longer pointing to valid memory, and when it later goes out of scope and is destructed you try to delete the already deleted memory.
There is no copy-construction going on here. It's all copy-assignment. Copy construction is only used on actual construction, when an object is created (temporary or not). I think you're confused because the = symbol can be used for copy-construction, as in
Vector a = b; // This is a copy-construction
// The copy-constructor of `a` is called with
// a reference to `b` as argument
// It's equal to `Vector a(b)`
This is very different from assignment
a = b; // This is a plain assignment
// It is equal to `a.operator=(b)`
The crash is solved by following one of the rules of three, five or zero.
I also recommend you read e.g. this canonical assignment operator reference.
You are creating a temporary Vector in the assignment a = Vector(12), which is being assigned via operator= to a. The temporary Vector gets destroyed at the end of the assignment statement, and a gets destroyed at the end of the function. Both point at the same allocated array because you did not define a copy-assignment operator=:
http://www.cplusplus.com/doc/tutorial/operators/
In Stroustrups The C++ Programming Language Fourth Edition, on page 76, there is example of move constructor use.
The class is defined like this:
class Vector {
private:
double∗ elem; // elem points to an array of sz doubles
int sz;
public:
Vector(int s) :elem{new double[s]}, sz{s}
{ for (int i=0; i!=s; ++i) elem[i]=0; // initialize elements }
~Vector() { delete[] elem; } // destructor: release resources
Vector(const Vector& a); // copy constructor
Vector& operator=(const Vector& a); // copy assignment
Vector(Vector&& a); // move constructor
Vector& operator=(Vector&& a); // move assignment
double& operator[](int i);
const double& operator[](int i) const;
int size() const;
};
The move constructor is defined:
Vector::Vector(Vector&& a) :elem{a.elem}, // "grab the elements" from a
sz{a.sz}
{
a.elem = nullptr; // now a has no elements
a.sz = 0;
}
Example execution which, I think, will cause memory leak:
Vector f()
{
Vector x(1000);
Vector y(1000);
Vector z(1000);
// ...
z=x; //we get a copy
y = std::move(x); // we get a move
// ...
return z; //we get a move
};
It seems that such move operation will cause memory leak, because y had been allocated 1000 elements in
Vector y(1000);
and simple pointer re-assignment at line y = std::move(x); would leave these initial 1000 ints pointed by y left on its own. I assume, the move constructor has to have extra line of code to de-allocate pointer 'elem' before moving.
Assuming the move constructor is implemented properly, no. The line you are refering to invokes move assignment, not constructor, because z already exists.
Is there a memory leak in this C++ move constructor?
No.
Example execution which, I think, will cause memory leak:
The shown execution calls move assignment, not move constructor.
I assume, the move constructor has to have extra line of code to de-allocate pointer 'elem' before moving.
It does not need to, because the pointer of the newly constructed object can not have pointed to any allocated memory before it was initialized with the value of the pointer from the move argument.
Yes, agree, this is move assignment: y = std::move(x);, not the constructor.
In the book they did not show it, just mentioned that move assignment is defined similarly.
But, in the move assignment definition, as I understand, we would need to deallocate elem, right? Something like this.
Vector& Vector::operator=(Vector&& a)
{
delete[] elem;
elem = a.elem;
sz = a.sz;
a.elem = nullptr; // now a has no elements
a.sz = 0;
}
and simple pointer re-assignment at line y = std::move(x); would leave
these initial 1000 ints pointed by y left on its own.
The address of the pointer to double is copied over to the new object (y) and the old object (x) has it's pointer set to nullptr. (It's happening in the move assignment method not shown)
I assume, the move constructor has to have extra line of code to
de-allocate pointer 'elem' before moving.
No deallocation needed here. The pointer is just 'moved' during assignment (it would also be moved during move construction). Cleanup of the double pointer should be handled by the destructor. In the case of x, the destructor would eventually fire on the nullptr. delete[] on a nullptr is a noop. see http://www.cplusplus.com/reference/new/operator%20delete[]/
The doubles allocated in y would however need to be cleaned out during the move assignment as pointed out.
I wrote the following dummy class to understand how the copy constructor,the copy assignment operator and the destructor works:
#include <string>
#include <iostream>
class Box {
public:
// default constructor
Box(int i=10,const std::string &t=std::string()) : a(i),s(new std::string(t)) {}
// copy constructor
Box(const Box &other) { a=other.a; s=new std::string(*other.s); }
// copy assignment operator
Box &operator=(const Box &other) { a=other.a; s=new std::string(*other.s); }
// destructor
~Box() { std::cout<<"running destructor num. "<<++counter<<std::endl; }
int get_int() { return a; }
std::string &get_string() { return *s; }
private:
int a;
std::string *s;
static int counter;
};
int Box::counter=0;
I'm using this class type in my code to test how it works but I was thinking about the implications in destroying objects which have a member of built-in pointer type:
#include "Box.h"
using namespace std;
int main()
{
Box b1;
Box b2(2,"hello");
cout<<b1.get_int()<<" "<<b1.get_string()<<endl;
cout<<b2.get_int()<<" "<<b2.get_string()<<endl;
Box b3=b1;
Box b4(b2);
cout<<b3.get_int()<<" "<<b3.get_string()<<endl;
cout<<b4.get_int()<<" "<<b4.get_string()<<endl;
b1=b4;
cout<<endl;
cout<<b1.get_int()<<" "<<b1.get_string()<<endl;
{
Box b5;
} // exit local scope,b5 is destroyed but string on the heap
// pointed to by b5.s is not freed (memory leak)
cout<<"exiting program"<<endl;
}
This pointer is initialized in the constructor to point to a (always new) dynamically allocated memory on the free store. So,when the destructor is called, members of the object to be destroyed are destroyed in reverse order. Is it right in this case, that only the int and the pointer objects are destroyed, and I end up having a memory leak (the string on the heap is not freed)?
Moreover, defining this copy assignment operator, do I have a memory leak every time I assign an object (the pointer points to a new object on the heap and the former is lost isn't it?) ?
Each time you call new, you have to delete it (except are shared pointers).
So you have to delete the string in the destructor.
The assignment operator works on an existing instance, so you already created s and do not have to create a new string for s.
the destructor destructs its members. Since a pointer is like a int, only the variable holding the address is destructed, not the object it is pointing to.
So yeah, you will have a memory leak in each object and everytime you use the assignment operator the way you designed your class.
Keep in mind allocation happens on base construction, copy construction and surprisingly conditionally on assignment
Deallocation happens in the destructor and conditionally on assignment
The condition to watch for is:
x = x;
So your code can be changed to the following pattern (in cases where you are not able to use the preferred appropriate smart pointer)
Box(int i=10,const std::string &t=std::string()) : a(i),s(new std::string(t)) {}
// copy constructor
Box(const Box &other) { cp(other); }
// copy assignment operator
Box &operator=(const Box &other) {
if (&other != this) // guard against self assignment
{
rm();
cp(other);
}
return *this;
}
// destructor
~Box() { rm(); }
private:
void cp(const Box &other) {a=other.a; s=new std::string(*other.s);
void rm() {
std::cout<<"running destructor num. "<<++counter<<std::endl;
delete s; // prevents leaks
}
One possible way to deal with unnamed dynamically allocated members is to save them in a container every time they are created (in an object, function, etc), and then to run a for loop in your destructor with a delete statement followed by the elements of the container.
You can do this with a vector:
vector <string*> container;
and you can use it as follows:
// define it in the private members of your class
vector <string*> container;
// use it when you create the string
container.push_back(new dynamicallyAllocatedObject);
// free memory in the destructor
for(auto it = container.begin(); it != container.end(); ++it) delete *it;
I got the follwing block of code:
#include <vector>
#include <iostream>
struct TestStruct {
bool wasCreated;
TestStruct() {
std::cout << "Default Constructor" << std::endl;
wasCreated = false;
}
~TestStruct() {
if (wasCreated) {
DoImportantStuff();
}
}
void Create() {
wasCreated = true;
}
// delete all copy stuff
TestStruct(const TestStruct&) = delete;
TestStruct& operator=(const TestStruct&) = delete;
// implement only move assignment & ctor
TestStruct(TestStruct&& other) {
std::swap(wasCreated, other.wasCreated);
}
TestStruct& operator=(TestStruct&& other) {
std::swap(wasCreated, other.wasCreated);
return *this;
}
// very important stuff
void DoImportantStuff() {
std::cout << "Do Important Stuff" << std::endl;
}
};
int main() {
std::vector<TestStruct> testVector;
testVector.emplace_back(TestStruct());
testVector.emplace_back(TestStruct());
std::cin.get();
}
This code leads to the output:
Default Constructor
Do Important Stuff
Default Constructor
Do Important Stuff
Do Important Stuff
Basicly I wanted to write a class, which owns memory but allocates this memory only when I call Create(). To avoid memory leaks and to avoid deleting not allocated memory I introduced wasCreated which will be only true when i call Create(). Every TestStruct should be saved in one vector. So in implemented move assigment & ctor and deleted both copy assigment & ctor.
Now it seems to me that the vector doenst call interally the default constructor of my TestStruct when its allocates new memory. Why is so and how do get the vector to call the default constructor on memory allocation? Do I need my own allocator?
Your problem is that your move constructor is implemented incorrectly. It swaps wasCreated between the newly created object and the one being moved from, but the variable in the newly created object has not been initialized yet (a default-constructed bool has an unknown value). So your temporary objects created with TestStruct() receive an uninitialized bool, which happens to be true in your case, hence the calls to DoImportantStuff() in their destructors.
So the move constructor should look something like this:
// implement only move assignment & ctor
TestStruct(TestStruct&& other) : wasCreated(other.wasCreated) {
other.wasCreated = false;
}
(You have moved ownership to the newly created object, the old one doesn't own anything anymore.)
Don't confuse the assignment operator with the constructor; they do different things. The assignment operator deals with two objects that are both already constructed; in the case of the constructor, the object being constructed is, well..., not constructed yet, so it doesn't have a valid state.
By the way, emplace_back() is pointless the way you're using it. Its purpose is to forward its arguments directly to the constructor of the object inside the vector. Since you have a default constructor (no arguments), the call should be:
testVector.emplace_back();
This will default-construct the TestStruct in place.
Now it seems to me that the vector doenst call interally the default constructor of my TestStruct when its allocates new memory.
A default-constructed vector has zero size, so there are no objects to construct.
If you want the vector to default-construct some objects, resize it.
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.