Is there a memory leak in this C++ move constructor? - c++

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.

Related

Implement a swap function to get a move constructor in own container class

In all standard containers like std::map or std::vector there is a move constructor and a move assignment to avoid copying. I want to build my own Wector class with the same functionalities. My class declaration looks as follows:
class Wector{
public:
~Wector();
Wector();
Wector(std::size_t s);
Wector(std::size_t s, const double nr);
Wector(const std::initializer_list<double> il);
//copy constructor
Wector(const Wector & w);
//move constructor
Wector(Wector&& w);
std::size_t size() const;
double* begin(); // iterator begin
double* end(); // iterator end
const double* begin() const; // const iterator begin
const double* end() const; // const iterator
const double& operator[](std::size_t i)const;
double& operator[](std::size_t i);
Wector& operator=(const Wector& w);
//move assignment
Wector& operator=(Wector&& w);
private:
std::size_t wsize;
void swap(Wector& w);
double *element; // double *element = new double[s]
};
To implement the move-assignment and constructor I need a customer swap.
//move constructor
Wector::Wector(Wector&& w)
: Wector()
{
swap(w);
}
//move assignment
Wector& Wector::operator=(Wector&& w){
swap(w);
return *this;
}
But I have no idea how to implement the swap function without having direct access to the data element and without copying with help of the iterators.
void Wector::swap(Wector& v){
std::swap(wsize, v.size());
double * temp = new double[v.size()];
std::copy(w.begin(), w.end(), temp);
std::swap(element, temp);
delete [] temp; //edited
}
Does anybody know how it is implemented in the case of std::vector?
You can just swap the pointers themselves (and, of course, the sizes). It doesn't matter which instance allocated the storage and which deletes it, it'll only belong to one instance at a time.
The swap you want will be something like:
void Wector::swap(Wector& v){
std::swap(wsize, v.wsize);
std::swap(element, v.element);
}
Your swap is not a move but a copy.
You can just move each member:
//move assignment
Wector& Wector::operator=(Wector&& w){
// instead of "delete element" we use the correct Destructor for delete the old data.
// But for this the swap method should be optimized by exchange just the pointer and the size!
Vector().swap(this); // old vector is swapped in temporary object and then cleaned up in destuctor
// members of w are accessible becasuse operator= is a class member function.
// NOTE: surround with std::move is superfluous here, I do it for clarity of expression/intention.
// Unfortunately the C++ standard does not reset the values to default, so we do it afterwards.
this->wsize = std::move( w.wsize );
this->element = std::move( w.element );
// set values of the moved object to 0
// (we must avoid double deleting element!)
w.wsize = 0;
w.element = nullptr;
return *this;
};
Same you can do for the Move Constructor.
EDIT fixed cleanup the old data.
EDIT well, this brings me to the right solution:
//move assignment
Wector& Wector::operator=(Wector&& w){
// *** using 2 swaps for make the move! ***
// But for this the swap method should be optimized by exchange just the pointer and the size!
// first exchange the values
this->swap( w );
// if swap did not throw (in this example the optimized swap can be made noexcept)
// this now has the new values and w the old.
// Now delete the old values by using a new temporary which will use the destructor for cleanup.
Vector().swap(w);
// w is empty now and old data deleted.
return *this;
};

Double free error on a C++ copy constructor

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/

operator overloading memory leak

Recently I got a task to do in C++, implement a Set class with union, intersection etc. as overloaded operators. I've got a problem with overloading an operator+(). I decide to use vectors and get the advantage of some algorithm's library functions. The problem is I HAD TO pass to constructor an array pointer and array size. This complicated this task a bit... I can compile it but during the "z=a+b" operation I encounter somekind of memory leak. Can anyone explain me what am I doing wrong?
class Set {
int number; // array size (can't be changed)
int *elems; // array pointer (same)
public:
Set();
Set(int, int*); // (can't be changed)
~Set();
friend Set operator+(const Set& X,const Set& Y){
std::vector<int> v(X.number+Y.number);
std::vector<int>::iterator it;
it=std::set_union (X.elems, X.elems+X.number, Y.elems, Y.elems+Y.number, v.begin());
v.resize(it-v.begin());
Set Z;
Z.number=v.size();
Z.elems=&v[0];
return Z;
}
};
Set::Set(){};
Set::Set(int n, int* array){
number=n;
elems = array = new int[number];
for(int i=0; i<number; i++) // creating Set
std::cin >> elems[i];
std::sort(elems, elems + number);
}
Set::~Set(){
delete[] elems;
}
int main(){
int* pointer;
Set z;
Set a = Set(5, pointer);
Set b = Set(2, pointer);
z=a+b;
}
I added copy constructor and copy assingment, changed the operator+() as NathanOliver advised and now I am passing to constructor static array. Still have memory leak and strange thing is that I got this memory leak even when in main there is only class variable initialization, doesn't matter if with parameters or not... Any suggestions? I think cunstructor is valid.
Set::Set(int n, int* array){
number = n;
elems = array;
std::sort(elems, elems + number);
}
Set::Set(const Set& s){
number=s.number;
elems=s.elems;
}
Set& operator=(const Set& X){
if(this==&X)
return *this;
delete [] elems;
elems=X.elems;
number=X.number;
return *this;
I use gcc (tdm64-2) 4.8.1 compiler.
In
friend Set operator+(const Set& X,const Set& Y){
std::vector<int> v(X.number+Y.number);
std::vector<int>::iterator it;
it=std::set_union (X.elems, X.elems+X.number, Y.elems, Y.elems+Y.number, v.begin());
v.resize(it-v.begin());
Set Z;
Z.number=v.size();
Z.elems=&v[0];
return Z;
}
You create a vector, modify it and then set the elems to point to what the vector contains. The issue with that is that when the vector is destroyed at the end of the function the memory that the vector held is released. So you now have a pointer pointing to memory you no longer own. Trying to do anything with it is undefined behavior. What you could do is create a new array, copy the elements of the vector into the array and then assign the new array to `elems
Set Z;
Z.number= v.size();
Z.elems= new int[z.number];
for (int i = 0; i < Z.number; i++)
Z.elems[i] = v[i];
return Z;
Secondly you need to define a copy constructor and assignment operator for you class. To do that reference: What is The Rule of Three?
The best solution (but I can't tell if you're allowed to do this specifically) is to use vector internally in your Set and assign it from the passed in pointer and length using the two-iterator constructor.
Now if that's not possible you need to properly manage the memory of your class:
You need a copy constructor and copy assignment operator.
In your operator+ you can't create a local vector and then take the address of its memory, that memory will disappear as soon as the operator returns.
Possibly other things I didn't catch.
When you have z=a+b, the assignment operator for the Set class is used. You didn't define a custom version of this operator, so the default compiler-generated one is used. This compiler-generated assignment operator=() simply does a member-wise copy.
Since you have raw owning pointers in your Set class, this doesn't work correctly: the default compiler-generated operator=() shallow-copies pointers, instead you should deep-copy the data.
An option to fix this is to define your own version of operator=(), paying attention to do proper deep-copy of source data.
Note that in this case you also should define a copy constructor.
But a better option would be to get rid of the owning raw pointer data members, and instead use a RAII building block class, like std::vector.
So, for example, instead of these data members:
int number; // array size (can't be changed)
int *elems; // array pointer (same)
you could just have a single:
std::vector<int> elems;
If you do that, the default compiler-generated operator=() will work just fine, since it will copy the std::vector data member (not the raw owning pointers), and std::vector knows how to properly copy its content without leaking resources.

Why do we need to delete pointers inside copy assignment operator

I have seen several examples of copy assignment operator and could not understand why do we need to delete pointers inside copy assignment operator. For example if I have the following class
class MyClass
{
public:
MyClass(int a)
{
x = new int(a);
}
MyClass& operator=(const MyClass& pMyClass)
{
*x = *(pMyClass.x);
// ?????????
// delete x;
// x = new int(*(pMyClass.x));
}
~MyClass()
{
delete x;
}
private:
int* x;
}
What is wrong with *x = *(pMyClass.x) line? I am just copying object pointed by pMyClass.x why I need to delete and create it again?. Could anyone please give example when this code will cause memory leak?
So this is an example [extracted from Bjarne Stroustrup's "A tour of C++ (2nd edition)] of a copy assignment of a user defined vector class:
Vector& Vector::operator=(const Vector& a) // copy assignment
{
double∗ p = new double[a.sz];
for (int i=0; i!=a.sz; ++i)
p[i] = a.elem[i];
delete[] elem; // delete old elements
elem = p; // here elem is the vector's data holding member array
sz = a.sz;
return ∗this;
}
To understand why at line 6 we have the deletion operation:
delete[] elem; // delete old elements
we first need to first understand the distinction between copy constructor and copy assignment. In the first case (copy constructor) we create a completely new object, whereas in the second case (copy assignment, the one we're actually interested in) we already have an existing object into which we just want to copy the contents of another given object of the same type.
Given the fact that we already have an existing object, we first need to clear it's contents so that we are then able to copy the desired content from the object we intent to copy.
I hope that answers your question.
It is a valid code. But if instead of the pointer to a single object you will have a pointer to first element of an array and arrays may have different sizes then you need to delete the array that to reallocate it with the new size.
Nothing wrong with *x = *(pMyClass.x) when you copying value from one class instance to other. I think, in general, deleting an object (if it is not just int) can prevent usage of new object with new data if before operator= execution address stored in x was sent to some other part of program.

STL vector insert - copy constructors

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.