copy constructor...what is wrong? - c++

So my problem is this...when I am trying to allocate memory to a pointer, it fails.
This is my MatrixClass definition..
class MatrixClass
{
public:
MatrixClass(int m, int n);
MatrixClass(void);
virtual ~MatrixClass(void);
double getRead(int num1, int num2) const;
double& getReadWrite(int num3, int num4);
void set(int i,int j,double value);//set value at i,j to value
MatrixClass(const MatrixClass &rhs);
void assign(int M,int N);
MatrixClass sum1(const MatrixClass& rhs) const;
MatrixClass operator+(const MatrixClass& rhs);//overloading the + operator
MatrixClass operator-();
private:
double* dataptr;
int M;
int N;
};
I am trying to do this..
MatrixClass BB;
BB = A + B;
So here is my overloaded + function..
MatrixClass MatrixClass::operator +(const MatrixClass &rhs)
{
MatrixClass temp;
//temp.M = this->M + rhs.M;
//temp.N = this->N + rhs.N;
for(int i = 0;i < M;i++)
{
for(int j = 0; j<N;j++)
{
temp.dataptr[i * N + j] = this->getReadWrite(i,j) + rhs.dataptr[i*N+j];
}
}
return temp;
}//end operator +
Once temp returns...it calls the copy constructor...passing temp as 'rhs' and 'this' would refer to 'BB'? (Am I right in thinking this?)
MatrixClass::MatrixClass(const MatrixClass &rhs)//copy constructor
{
this->M = rhs.M;
this->N = rhs.N;
dataptr = 0;
if(rhs.dataptr != 0)
{
dataptr = new double[M * N];//allocate memory for the new object being assigned to...
// the line here where I try to allocate memory gives me an error.....Am I right in
//thinking that this would be assigning memory to dataptr of 'BB'?? Values are assigned to //'M' and 'N' fine....
int num = sizeof(double);
memcpy(this->dataptr,rhs.dataptr,M*N*sizeof(double));
}
else
{
this->dataptr = 0;
}
}//end copy constructor
Also the error that i get is this... 'Unhandled exception at 0x75a0b727 in assignment.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x002af924..'
So basically the qestion I am asking is..why the hell is is the line where I am trying to allocate memory to 'dataptr' in the copy constructor giving me problems..it only does this when calling the copy constructor from the return value 'temp'..
Thanks!

Short answer: you have not implemented Rule of Three properly. In C++11, Rule of Five.
Long answer: you have not implemented operator=. The compiler generated one is not enough for your case.
Apart from that my guess is that your default constructor doesn't allocate memory for dataptr. If so, then you're using dataptr in operator+ without even allocating memory for it. That is the reason why your program crashes. Even if the default constructor allocates memory, the problem is still there as the value of rhs.M and rhs.N may be different from what you assume in the default constructor (which is, as you said, 4 and 5 respectively).
So allocate memory for dataptr in operator+. Also, before allocation, you've to deallocate the memory which it may point to, and you also need to set M and N to the values of rhs.M and rhs.N respectively.

No, James, you're wrong, when operator+ returns the copy constructor will be called to covert local variable temp into a temporary anonymous object in the scope of the assignment operator. In the copy constructor, this will refer to this temporary variable, not BB.
Because the LHS already exists, it will not be "constructed" again when operator+ returns, it will be "assigned", so you need to overload operator=. (See here for much more detail.) The default operator= just makes a bitwise copy, so if you didn't overload operator=, the dataptr would be freed (we hope) in the destructor of the anonymous temporary object when it is destroyed as it goes out of scope (which is immediately after it is copied) and BB would be pointing to freed memory. You would also leak any memory already allocated in BB as BB would not be destroyed before being assigned. BB's dataptr would leak while the temporary object's dataptr would be freed twice.
So, although it kind of sucks that you end up allocating and copying memory three times, in order to make + and = work in all situations, you need to do the following:
In operator+ change MatrixClass temp; to MatrixClass temp(rhs.M, rhs.N); so that temp.dataptr is properly allocated and deallocated.
As you are doing, in the copy constructor allocate new memory for dataptr and copy it over.
Overload operator= so that it first checks for self-assignment (this == &rhs) and if it is not self-assigning, frees the existing dataptr and then allocates a new one and copies the rhs.

Related

Assignment operator crashes code while i make template of class

I'm making a template for vector class in which I'm making vector from an array. But within the class the assignment operator is crashing the code as I can see the return value is some ( Process returned -1073741819 (0xC0000005)).
int i=0;
const int size = 4;
template<class T>
class vector{
public:
vector()
{
x = new T[size];
for(i=0;i<size;i++)
x[i] =0 ;
}
vector( T *a) // This part is creating issue if i comment it out code
// successfully return with value Zero. But with this it doesn't work at all.
{
// cout<<"called";
for(i=0;i<size;i++)
{
x[i] = a[i];
}
}
T operator *(vector &y)
{
T sum = 0;
for(i=0;i<size;i++)
{
sum += this->x[i] + y.x[i];
}
return sum;
}
private:
T * x; // Type of vector;
};
int main()
{
int arr1[4] = {2,3,4,5};
int arr2[4] = {6,7,8,9};
vector<int> v1;
vector<int>v2;
v1 = arr1; // This call is the culprit. it doesn't work t all.
v2 = arr2;
return 0;
}```
You have several issues that lead to the crash and other problems.
The first is that the statement
v1 = arr1;
is equivalent to
v1 = vector<int>(&arr1[0]);
That means a temporary vector<int> object will be created, which invokes the vector(T *a) constructor.
And here the problems start: Because it's a constructor, the object being constructed is uninitialized, as it's the purpose of the constructor to initialize it. That means the member variable x will also be uninitialized and will not be pointing to a valid location.
You need to allocate memory and make x point to that memory, otherwise you dereference the uninitialized pointer which leads to undefined behavior and very likely your crash.
As for the other problems, first of all you miss a destructor, which means that memory allocations don't have anywhere to be free'd. Which in this case actually is good, because since you don't have an actual assignment operator (and rely on the compiler generated assignment operator) the copying in v1 = arr1 will be a shallow copy, that copy only the pointer itself and not the memory it points to.
The shallow copy problem means that for a while you will have two objects whose x member will point to the same memory. And if one object deletes that memory (like when the temporary object mentioned above is destructed) then the second pointer in v1 will no longer be valid.
This is the reason behind the rules of three and five.

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/

Destructor of object cause crashing

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.

Will this addition class cause a memory leak?

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).

C++ operator destroys input variables

This is probably just me being stupid somehow or the other, but I am relatively new to C++, so forgive me the idiocy. I'm trying to teach myself how to use operators. I've defined a very basic operator as follows:
Matrix::Matrix operator+(Matrix a1, Matrix a2) {
if(a1.rows != a2.rows || a1.cols != a2.cols) {
std::cout << "ERROR: Attempting to add matrices of non-equal size." << std::endl;
exit(6);
}
int i, j;
Matrix c(a1.rows, a1.cols);
for(i = 0; i < a1.rows; i++)
for(j = 0; j < a1.cols; j++)
c.val[i][j] = a1.val[i][j] + a2.val[i][j];
return c;
}
The class Matrix represents a matrix, and has a constructor that takes two ints as input (the number of rows and columns in the matrix, respectively), and creates a 2D array of doubles of the appropriate size (named val). This function works as supposed to in that the value for c is correct, but it also appears to destruct a1 and a2. That is, if I write
Matrix c = a + b;
It gives the right result, but a and b are no longer usable, and I get a glibc error at the end of the code claiming I am trying to destruct a and b when they have already been destructed. Why is this?
Your signature is wrong:
Matrix operator+(Matrix a1, Matrix a2)
it should be
Matrix operator+(const Matrix& a1, const Matrix& a2)
The reason it appears to destroy a1 and a2 is because, well, it is, since those are temporary copies created in the method scope.
If the original values are destroyed, you're probably violating the rule of three. When a1 and a2 are destroyed, the destructor gets called, and you're probably deleting pointers in the destructor. But since the default copy constructor does only a shallow copy, the copied a2 and a1 will delete the original memory.
Edit: Since there are split opinions about this, I'll extend my answer:
Assume:
struct A
{
int* x;
A() { x = new int; *x = 1; }
~A() { delete x; }
};
//option 1:
A operator + (A a1, A a2)
{
A a; return a; //whatever, we don't care about the return value
}
//option 2:
A operator + (const A& a1, const A& a2)
{
A a; return a; //again, we don't really care about the return value
}
In this first example, the copy constructor is not implemented.
A copy constructor is generated by the compiler. This copy constructor copies x into the new instance. So if you have:
A a;
A b = a;
assert( a.x == b.x );
Important note that the pointers are the same.
Calling option 1 will create copies inside operator +, because the values are passed by value:
A a;
A b;
a + b;
//will call:
A operator + (A a1, A a2)
// a1.x == a.x
// a2.x == n.x
When operator + exits, it will call delete x on objects a1 and a2, which will delete the memory that is also pointed to by a.x and b.x. That is why you get the memory corruption.
Calling option 2 however, since no new objects are created because you pass by reference, the memory will not be deleted upon function return.
However, this isn't the cleanest way to solve the issue. It solves this issue, but the underlying one is much more important, as Konrad Pointed out, and I have in my original answer (although haven't given it enough importance, I admit).
Now, the correct way of solving this is properly following the rule of three. That is, have an implementation for destructor, copy constructor and assignment operator:
struct A
{
int* x;
A() { x = new int; *x = 1; }
A(const A& other) //copy constructor
{
x = new int; // this.x now points to a different memory location than other.x
*x = other.(*x); //copy the value though
}
A& operator = (const A& other) //assignment operator
{
delete x; //clear the previous memory
x = new int;
*x = other.(*x); //same as before
}
~A() { delete x; }
};
With this new code, let's re-run the problematic option 1 from before:
A a;
A b;
a + b;
//will call:
A operator + (A a1, A a2)
// a1.x != a.x
// a2.x != n.x
Because the copies a1 and a2 now point to different memory locations, when they are destroyed, the original memory is intact and the original objects - a and b remain valid.
Phew! Hope this clears things up.
I’m assuming that you are allocating dynamic memory inside the Matrix class using new and didn’t implement a custom copy constructor, thus violating the rule of three.
The cause of the error would then be that the local copy of the Matrix instances reuses the dynamic memory of the argument instances, and their destructors free it at the end of the method.
The solution is very simple: Don’t use pointers. Instead, you could use a nested std::vector to store the data.
Furthermore, the head of the operator is mangled. Depending on where you declare the function, it must either look like this, if you define the operator inside the class:
ReturnType operator +(Arg1)
Or, if you define it outside the class, it needs to look like this:
ReturnType operator +(Arg1, Arg2)
Yours is a wild mix of both. I’m assuming that your operator definition should look as follows:
Matrix operator +(Matrix a, Matrix b) { … }
If your code compiles then this is either an error in the compiler or you are using a very weird class structure indeed. Furthermore, as Luchian pointed out, it’s more efficient to pass the arguments as const& rather than by value. However, you should first make your code run correctly.
As Luchian Grigore pointed out, your signature is wrong and should be:
Matrix operator+(const Matrix& a1, const Matrix& a2)
But even this signature should not itself spoil a and b. But because you are copying arguments, I have another suspicion.
Have you defined your own copy constructor? I think you may be deleting the old variables when you are copying their values to the operator's arguments.
Please share your copy constructor (and preferably also operator= and the two-argument constructor that you use in this operator)
Since the size of the matrix is given at runtime, I suppose that the Matrix class hold a pointer that is initialized with a dynamically allocated array that is deleted by the destructor.
In that case, the copy constructor and the assignment operator must also be definedin order to allocate the copies of what the a matrix holds.
Not doing that, the default copy and assignment will just reassign the pointers, letting you with two or more Matrix holding a same array. And when one is destroyed (thus deleting the array) the others remain dangling.