I wrote a simple vector class which overloads assignment and addition operators. The code adds two vectors and prints vectors before and after the addition. Surprisingly destructor ~MyVector() is being called after the line c=a+b. I do not see the reason why is it so, as neither of objects a,b and c gets out of scope. Do you understand the reason for invocation of the destructor?
#include<iostream>
#include<cstdlib>
using namespace std;
template<typename T>
class MyVector
{
public:
MyVector(int s)
{
size=s;
a=new T[s];
}
~MyVector()
{
delete[] a;
size=0;
};
void freeVec()
{
cout<<"Calling destructor. a[0]= "<<a[0]<<endl;
if(a!=NULL)
{
free(a);
a=NULL;
}
}
int getSize(void)
{
return size;
}
void setSize(int ss)
{
size=ss;
}
T &operator[](int i)
{
return a[i];
}
MyVector &operator=(MyVector mv)
{
if(this==&mv)
return *this;
for(int i=0;i<mv.getSize();i++)
this->a[i]=mv[i];
this->size=mv.getSize();
return *this;
}
MyVector operator+(MyVector &mv)
{
for(int i=0;i<size;i++)
{
this->a[i]+=mv[i];
}
cout<<endl;
return *this;
}
private:
int size;
T *a;
};
int main(void)
{
MyVector<int> a(3),b(3),c(3);
a[0]=1;a[1]=2;a[2]=3;
b[0]=4;b[1]=5;b[2]=6;
cout<<"initial vector"<<endl;
for(int i=0;i<3;i++)
cout<<a[i]<<" ";
cout<<endl;
for(int i=0;i<3;i++)
cout<<b[i]<<" ";
cout<<endl;
c=a+b;
cout<<"final vectors"<<endl;
for(int i=0;i<3;i++)
cout<<a[i]<<" ";
cout<<endl;
for(int i=0;i<3;i++)
cout<<b[i]<<" ";
cout<<endl;
for(int i=0;i<3;i++)
cout<<c[i]<<" ";
cout<<endl;
cout<<endl;
return 0;
}
Your a + b returns a nameless temporary object that consequently gets copied to c (by the assignment operator) and then gets destructed. That's the destructor call that you see.
Also, your assignment operator receives it parameter by value (why???), which means that theoretically another copy can be created for that as well. Your compiler apparently optimized out that copy, which is why you see only one additional destructor call.
BTW, since you manually manage allocated memory in your object, it is a very good idea to implement copy constructor as well, in accordance with the "Rule of Three". The current version of the class (without copy constructor) can easily be used to build broken code specifically because the copy constructor is missing. In fact, your current code is already broken, since it uses compiler-provided copy constructor for copying your class object. The only reason you don't see any crashes is because the compiler optimized out (elided) most of the copies and, probably, because you got lucky.
On top of that your implementation of binary + modifies the data stored in *this object (why???), meaning that c = a + b modifies a. This is not exactly what people expect to see as a typical behavior of binary + operator.
There are lots of other bizarre things in your code. For example, what is freeVec and why is it trying to use free on memory that is always allocated by new[]? Also, why does the destructor set size to 0? What is the point of that?
Because your MyVector operator+(MyVector &mv) creates a copy (as it should do). This temporary copy is destroyed once it has been stored in c.
Note that modifying this in operastor+ is not a great plan. You don't expect a to become the same value as c from c = a + b;.
In the line c = a + b; there are actually 2 operations. The first is the addition. They way you have implemented it, a is actually incremented by the value of b. A copy of a is then returned in the line return *this;. This copy is not yet assigned to c; it is a nameless temporary.
In the assignment call, this copy is passed by value, thereby creating another copy. However, with copy elision, I believe it's possible the second copy is optimized out, so in total 1 copy is created. Thus the input to the assignment operator is a copy of an object. That object would get destroyed when the assignment operator returns.
Somewhat orthogonal to your question, I want to point out that there are a number of issues with the way you have implemented the operators. Firstly, your + operator is modifying the object that it is associated with. In the line c = a + b; the value of a gets modified because of the line this->a[i]+=mv[i]; in your function, which I believe is not your intended effect.
Secondly, in your implementation of the = operator, the lines
if(this==&mv)
return *this;
are useless because mv was passed by value and will never have the same address as this anyway.
Related
I'm trying to make me clear about move semantics. I'm following examples of the Bjarne Stroustrup book 4th edition and I'm really lost.
He says that copy of objects can be expensive when a lot of elements (in class vector) so move semantics is the solution.
Think something like:
Vector result = vector1 + vector2 + vector3;
Order may be wrong but it will do (vector2 + vector3) generating partial result result1, and result1 + vector1, generating result;
I overloaded operator+:
Vector operator+(const Vector &a,const Vector &b)
{
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
Vector result(a.size());
cout << "Intermediate result for sum created" << endl;
for(long unsigned int i=0; i<result.size();i++){
result[i] = a[i] + b[i];
}
return result;
}
I also created a move constructor:
Vector::Vector(Vector&& orig) noexcept
:elem{orig.elem},
sz{orig.sz}
{
cout << "Move constructor called" << endl;
orig.elem = nullptr; // We own the array now
orig.sz = 0;
}
So no copy operations are performed. But there are some things I don't understand. One is related to just c++ and the other to c++11.
So first:
As you can see, when operator+ exits Vector result should be destroyed. But not after the contents are copied to another instance of vector. What I called partial result1.
This never happens, the output of the program is like this:
New class vector created <-- Constructor of partial result 1
Intermediate result for sum created <-- Operator+ applied
New class vector created <-- Constructor of partial result 2 -> goes to result
Intermediate result for sum created <-- Operator+ applied
Class vector destroyed <-- I undenderstand that partial result 1 destroyed.
But I don't see the second partial result destroyed until the end of the program. Nor I see any copy operations (I have done operator= and copy constructor).
So I don't understand that. If the scope of the variable Vector result is inside operator+ the contents MUST be copied to another variable. That's not done. It seems that last result of the sum is just assigned to Vector result of the sum.
Second:
No move operations are performed. I cannot get move semantics to work here. I took a look to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52745 and applied what's there but no move operations anyway.
Every result is right.
So clearly, there is something I'm doing wrong.
You can grab the whole code (with autotools config + eclipse) from here:
http://static.level2crm.com/cx11-learn-20140218.tar.bz2
Can someone explain what happens here?
Best regards,
First and foremost, there is no move-construction here. There is NRVO occurring (as per comments on your question) but if you want to testify of move-construction occurring, you should try to copy a temporary. Try re-implementing your operator as follows:
// Note that the first parameter is taken by value.
Vector operator+(Vector a, const Vector &b)
{
cout << "Intermediate result for sum created or moved from a" << endl;
// NOTE: Could be implemented as operator+= and written a += b.
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
for(long unsigned int i=0; i<a.size();i++){
a[i] += b[i];
}
// END NOTE
return a;
}
Note that your operator now requires a local "copy" as first parameter. On the first sum, since a Vector& will be provided as argument (the object has a name), the copy constructor will be called and create an object with a new buffer (what you are doing with your result local variable). Then, a temporary will be formed, so on the second call to your operator+, a Vector&& will be provided as first argument and the move-constructor will be called, effectively stealing the buffer of the temporary.
If you prevent constructor elision as per comments, you should be able to see some move constructors called.
EDIT: A more detailed explanation of why you won't have a move in your case. The short version is that C++ does not do magic :)
The aim of a move in the case of chained additions is to avoid repeatedly creatingthe buffers of your Vectors due to the creation of temporaries. Instead of losing the buffers to the destruction of the temporaries, the aim is to reuse the buffer of the temporary to store the result.
In your case, you're not even trying to copy the buffer of the Vector. You're explicitly creating a new buffer on this line:
Vector result(a.size());
You're saying "Please create a vector of the right size for the result", and doing it once for every addition. You had better say "Please steal the buffer of a" if you know that a will die soon. It is written:
Vector result(a);
But for this to work, a must refer to an object that will die soon, and this means a must be of type Vector&&. When this is done, result already contains the values of a, so all you have to do is add the values of the elements of b.
for(long unsigned int i=0; i<result.size();i++){
result[i] += b[i];
}
(Expressing + in terms of += is idiomatic)
So to testify of move construction, you should have a definition of your operator+ whose signature is:
Vector operator+(Vector&& a, const Vector &b) {
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
Vector result(a);
cout << "Intermediate result for sum moved from a" << endl;
for(long unsigned int i=0; i<result.size();i++){
result[i] += b[i];
}
return result;
}
But this won't work with the first addition, since it is not adding a temporary to another named object, but two named objects. You should have an overload of your operator+ that copes with lvalue references:
Vector operator+(const Vector& a, const Vector &b) {
if(a.size()!=b.size()) {
throw length_error{"Length of vectors must match for summing"};
}
Vector result(a); // In this case, this is a copy
cout << "Intermediate result for sum created" << endl;
for(long unsigned int i=0; i<result.size();i++){
result[i] += b[i];
}
return result;
}
Notice that both versions share the same text. Which brings to another idiomatic way of doing: letting the compiler decide of whether to do the move or the copy by requiring the left side of operator+ to be passed by value, requiring only one overload. (This is the version at the beginning of my answer.
When does the object Second go out of scope? If I leave the third cout statement I get a compiler error. Even when I surround the initialization of Second and the cout statements.
#include <iostream>
using namespace std;
class MyArray{
public:
int Size;
int* data;
MyArray(int s) : Size(s), data(new int[s]){}
~MyArray(){
delete[](this->data);
}
};
int main()
{
MyArray First(20);
First.data[0] = 25;
MyArray Second = First;
cout << First.data[0] << endl;
cout << Second.data[0] << endl;
cout << Second.data[0] << endl;
system("PAUSE");
return 0;
}
The runtime error:
Here is what's going on: MyArray objects get a pointer to their own array of integers called data upon initialization. However, this line changes things for the Second object:
MyArray Second = First;
Now both First.data and Second.data point to the same int[] array, because the default copy constructor and assignment operator perform a shallow copy.
This is bad, because the compiler has freedom to destroy First after its last use in your code. Hence, accessing Second.data[0] may be invalid already.
Moreover, once First and Second go out of scope at the end of main(), they both will try deleting data. Only the first one would succeed; the second one will trigger undefined behavior.
To avoid such errors in the future, use the rule of three. It says that if you define a destructor, a copy constructor, or an assignment operator, you probably need all three of them.
Your code has only the destructor. Adding a copy constructor and an assignment operator will fix this problem, and prevent memory leaks on assigning MyArray objects.
The scope of both names ends at the }. (Scope is a compile-time notion.)
The lifetime of Second ends when execution reaches the end of the block, after which the lifetime of First ends. But your program has undefined behaviour because you delete the array twice, so anything can happen.
You need to do the deep copy using copy constructor
MyArray(const MyArray &t)
{
t.size = size;
if(size not_eq 0)
{
t.data = new int(size);
for(int i=0 ; i<size ; i++)
t.data[i] = data[i];
}
}
after this MyArray Second = First; will work fine
if you want to assign then you have to write assignment operator as well
I'm a noob in c++. I have a problem that I cannot solve anyway. I wrote a code to understand better classes and overload operator:
#include <iostream>
#include <stdlib.h>
#include <stdarg.h>
using namespace std;
class vectmy {
public:
int size;
int *a;
vectmy(int n,int val);
~vectmy (){delete[] a; //IF I DELETE THIS PROGRAM WORKS
}
vectmy & operator = (const vectmy &);
};
vectmy::vectmy(int n,int val){
size=n;
a = new int[ n+1 ];
for (int i=0;i<n;++i){
*(a+i)=val;
}
}
vectmy& vectmy::operator= (const vectmy& param)
{
for (int i=0;i<3;++i) a[i]=param.a[i];
return *this;
}
vectmy operator+( vectmy left, vectmy right)
{
vectmy result = left;
for (int i=0;i<3;++i) result.a[i]=result.a[i]+right.a[i];
return result;
}
int main() {
int b1[3]={1,2,4};
vectmy d(3,2),b(3,4),c(3,0);
c=(b+d);
for (int j=0; j<3; ++j)cout<<c.a[j]<<' '<<endl;
return 0;
}
When I run it crashes. If I remove the destructor it works. Why it happens?
When I run it crashes. If I remove the destructor it works. Why it happens?
Your operator + creates a copy of left here:
vectmy result = left;
Since you haven't defined a copy constructor explicitly, the compiler will generate one implicitly that performs member-wise copying.
A dull copy of the a data member means that the a pointer will eventually point to the same location for two different instances of vectmy (result and left), both of which will delete[] it upon destruction.
Such double deletion gives your program undefined behavior, which in your case manifests itself as a crash.
This is the point of the Rule of Three: every time you have a user-defined copy-constructor, assignment operator, or destructor, you should probably define all of them.
The reason is that you normally define one of those functions because you are managing some resource (memory, in your case), and you usually want to perform proper actions when copying, destructing, or assigning objects that manage a resource.
In this particular case, a proper copy constructor is missing. This is how you could define it:
vectmy::vectmy(vectmy const& v)
{
size=v.size;
a = new int[size];
*this = v;
}
Also, I would suggest you to avoid manual memory management through raw pointers, new, and delete (or their array counterparts) whenever you can, and consider using std::vector instead.
UPDATE:
Also notice, that your operator + is accepting its parameters by value, which means that each argument will be copied (i.e., the copy constructor will be invoked).
Since a copy is not really necessary here, you may want to take your parameters by reference (to const):
vectmy operator + ( vectmy const& left, vectmy const& right)
// ^^^^^^ ^^^^^^
In your operator+ you do
vectmy result = left;
This will call the default constructor and copy constructor, of which you have none. So the compilers variants will be used, which doesn't allocate memory for the a member. For the automatically generated copy constructor the pointer will simply be copied, making two object use the same pointer. When one deletes it, the other pointer becomes invalid.
You should read about the rule of three.
Here is an example of a class that is made available for the + operation.
class A
{
public:
int *array;
A()
{
array = new int[10];
}
~A()
{
delete[] array;
}
A operator+ (const A &b)
{
A c;
for(int i=0; i<10; i++)
c.array[i] += array[i] + b.array[i];
return c;
}
};
int main()
{
A a,b,c,d;
/* puts some random numbers into the arrays of b,c and d */
a = b+c+d;
}
Will a run the destructor before copying the result of b+c+d or not? If not, how do I make sure no memory is leaked?
The + operator overload is designed this way such that no operand is modified.
You need to add an equals operator to A. Also, you will likely want to create a copy constructor.
When a becomes the return from b+c+d, the array pointer in a gets over written without delete[] ever being called on it. You need to make an operator= that deletes the array.
An example of an operator= is below:
A& operator=(A const& a)
{
if (&a != this) {
int* tmp = this->array;
this->array = new int[10];
//copy a.array to this->array
delete[] tmp;
}
return *this;
}
There's a lot of subtleties in this if you're new to operator=.
In particular, the check whether or not a is equal to this is necessary because it's perfectly valid to write:
A a;
a = a;
This would cause a pointless copy, and in most cases of operator= will cause bugs.
The other subtlety is less of a requirement than that one and more of a coding style (though a very wide spread standard). When copying something that is dynamically allocated, you always want to allocate and copy before you release. That way, if new throws an exception (or something else fails), the object is still in a stable state, though with it's old data instead of the new expected dated.
Will this cause memory leak?
Yes, it will. You forgot to add copy constructor and assignment operator. See Rule of Three
You could also use std::vector<int> for A::array instead of int*. In this case you wouldn't need to worry about copy constructor/assignment operator (as long as you don't add something else that must be handled in destrcutor).
I was trying to write a matrix class which would be able to find inverse,adjoint,etc. of a square matrix of any order.
The constructor initializes an identity matrix of order n(passed to it).
class Matrix
{
int** elements;
int order;
public:
Matrix& operator=(const Matrix& second_inp)
{
if(this->order!=second_inp.order)
cout<<"The matrix cannot be assigned!!!\n"<<this->order<<"\n"<<second_inp.order;
else
{
for(int i=0;i<this->order;i++)
for(int j=0;j<this->order;j++)
this->elements[i][j] = second_inp.elements[i][j];
}
return *this;
}
Matrix operator*(const Matrix& a)const
{
Matrix c(a.order);
for(int i=0;i<c.order;i++)
for(int j=0;j<c.order;j++)
c.elements[i][j]=0;
if (this->order!=a.order)
{
cout<<"The 2 Matrices cannot be multiplied!!!\n";
return Matrix();
}
else
{
for(int i=0;i<a.order;i++)
for(int j=0;j<a.order;j++)
for(int k=0;k<a.order;k++)
c.elements[i][j] += (this->elements[i][k])*(a.elements[k][j]);
return c;
}
}
};
~Matrix()
{
for(int i=0;i<this->order;i++)
delete[] *(elements+i);
delete[] elements;
elements=nullptr;
}
If i were to run the following code using this class:
Matrix exp1(2),exp2(2),exp3(2);
exp1.get_matrix();
exp3=exp1*exp2;
exp3.show_matrix();
I get a run-time error, while debugging i found out that, after the multiplication(exp1*exp2) the =operator was not able to access the data if the result of the *operator.
But if i were to use a manual destructor like this one at the end of the main() to free all allocated memory, the program works fine.
void destroctor()
{
for(int i=0;i<order;i++)
delete[] *(elements+i);
delete[] elements;
}
how can i edit the destructor or the operator overloads to correct this problem?
The constructor i used:
Matrix(int inp_order):order(inp_order)
{
elements=new int*[order];
for(int i=0;i<order;i++)
*(elements+i)=new int[order];
for(int i=0;i<order;i++)
for(int j=0;j<order;j++)
{
if (i==j)
*(*(elements+j)+i)=1;
else
*(*(elements+j)+i)=0;
}
}
It is hard to tell what is going wrong, since you have not posted your constructors.
In the exp3=exp1*exp2; a lot of things happen:
First a new matrix c is constructed in the operator* function. Then the return c; statement calls the copy constructor and then the destructor. After that operator= is called and after that the destructor for the temporary matrix again.
I think what happens is that you are using the default copy constructor which does not make a deep copy. That way the destructor being called at the time of return c deletes the data that still shared between the matrices.
I get a run-time error, while debugging i found out that, after the multiplication(exp1*exp2) the =operator was not able to access the data if the result of the *operator.
You didn't show us your constructor, so there is no way to tell why you are getting this errors.
I suspect that the cause is that you aren't allocating the memory needed to contain your matrix. You declared it as an int**, so you need to allocate an array of int* pointers, and for each of those you need to allocate an array of int.
Edit
While I was typing this you posted code for your constructor.
You are not returning a value from your overload of operator*, and you don't have a copy constructor (rule of three).
Do you have compiler warnings enabled? Any compiler worth its salt would have complained about the missing return statement in the operator overload.
You have not defined a copy constructor, so the compiler will generate one for you. This constructor will be called in order to copy the return value of operator*(const & Matrix a) into the result.
As the generated copy constructor only performs a shallow memberwise copy, it will not allocate a new array of elements, hence the error.