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.
Related
So, for instance, I have the following code which I want a object's pointer
member to point to a memory which was pointed by another temporary object's
member.
struct A {
int * vals;
A(): vals(new int[10]) { }
~A(){ delete[] vals; }
};
int main() {
A a;
{
A temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = 100;
}
a.vals = temp.vals;
temp.vals = nullptr; // avoid double free
}
I set temp.vals to nullptr in case the destructor of temp will free that
memory. So far so good, I guess. However, if I change the vals to a dynamic
array, i.e. a pointer to pointers:
struct A {
int ** vals;
A(): vals(new int*[10]) {
for (int i = 0; i < 10; ++i) {
vals[i] = new int;
}
}
~A(){
for (int i = 0; i < 10; ++i) {
delete vals[i]; // illegal to dereference nullptr
}
delete [] vals;
}
};
int main() {
A a;
{
A temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = new int(1);
}
a.vals = temp.vals;
temp.vals = nullptr; // avoid double free
}
}
I have add a for loop in destructor to handle the nested allocated memory, and
to avoid the memory be freed by the destructor of temp, I set temp.vals to
nullptr, which, however will cause a segmentation fault since when destructor
of temp is called, it is illegal to dereference a nullptr.
So my question is, how to correct set the destructor to handle the dynamic array.
I'm not a native speaker, so please forgive my grammar mistakes.
The typical C++ solution looks a bit different:
class A {
private:
int* vals;
public:
A(): vals(new int[10]) { }
~A(){ delete[] vals; }
A (A const& src); // Copy constructor
A (A&& src) : vals (src.vals) { src.vals = nullptr; }
A& operator=(A const&); // Assignment
A& operator=(A &&);
};
You can now write a = std::move(temp). Outside the class, you don't need to know how the inside works.
For your 2D array, just define the same special member functions. This is usually called the "Rule of Five". If you need a destructor, you probably need the other 4 functions as well. The alternative is the "Rule of Zero". Use std::vector or another class that manages memory for you.
However, if I change the vals to a dynamic array, i.e. a pointer to pointers
In the first program, vals is a pointer. It points to a dynamic array of integers. In the second program, vals is also a pointer. It points to a dynamic array of pointers.
how to correct set the destructor to handle the dynamic array.
You set vals to null. If null is a valid state for vals, then it isn't correct to unconditionally indirect through it in the destructor. You can use a conditional statement to do so only when vals isn't null.
However, the program is hardly safe because vals is public, and thus it is easy to mistakenly write a program where it is assigned to point to memory that isn't owned by the object. In cases where destructor cleans up an owned resource, it is important to encapsulate the resource using private access to prevent accidental violation of class invariants that are necessary to correctly handle the resource.
Now that vals is no longer outside of member functions, you cannot transfer the ownership like you did in your example. The correct way to transfer the ownership is to use move assignment (or constructor). The implicitly generated move constructor cannot handle an owning bare pointer correctly. You must implement them, as well as the copy assignment and constructor.
Furthermore, you should use an owning bare pointer in the first place. You should use a smart pointer instead. If you simply replaced the bare pointers with unique pointer, then the implicitly generated move assignment and constructor would handle the resource correctly, and the copy assignment and constructor would be implicitly deleted.
Lastly, the standard library has a container for dynamic arrays. Its called std::vector. There's typically no need to attempt to re-implement it. So in conclusion, I recommend following:
std::vector<int> a;
{
std::vector<int> temp;
for (int i = 0; i < 10; ++i) {
temp.vals[i] = 1;
}
a = std::move(temp);
}
There are still issues such as the temporary variable being entirely unnecessary, and the loop could be replaced with a standard algorithm, but I tried to keep it close to the original for the sake of comparison.
P.S. It's pretty much never useful to dynamically allocate individual integers.
class Vect {
public:
Vect(int n);
~Vect();
Vect(const Vect& original);
private:
int* data;
int size;
};
Vect::Vect(int n) {
size = n;
data = new int[n];
}
Vect::~Vect() {
delete [] data;
}
Vect::Vect(const Vect& original) {
size = original.size;
data = new int[size];
for (int i = 0; i < size; ++i) {
data[i] = original.data[i];
}
}
#include <bits/stdc++.h>
using namespace std;
int main(void) {
Vect a(100);
Vect b = a;
Vect c;
c = a;
return 0;
}
I have a Vect class now, in main I created a Vect object that variable c holds, what will be the default size of c.size ??
Or It won't have any default?
If it does not have a default value then how does b have 100 (as in a.size is now equals b.size)?
What will be the default size of c.size ??
There is no default value except if you provide one. You should have a default constructor if you want to cover it (otherwise using uninitialized variable is undefined behaviour).
For example:
Vect::Vect() : data(nullptr), size(0)
{}
If it does not have a default value then how does b have 100 ?
Actually, when you write Vect b = a;, it is equivalent as Vect b(a);. In other words, the copy constructor is called (this is copy-initialization).
However, when you write:
Vect c;
c = a;
This is a copy-assignment. And you didn't provide one which is a problem because you need to handle the dynamic allocation of the data member (prevent self-assignment, deallocate if not nullptr and then reallocate with the new content), etc...
You should define the operator=() for the Vect class for your program to be well-formed.
To answer your question: There is no default value of Vect::size unless you provide a default one in the class declaration, like
int size = 0;
If you do not initialize Vect::size you incur in undefined behavior.
Further, this code has a lot of problems, and in fact it does not compile.
Essential problems:
There is no constructor of Vect with no parameters, and there is not implicitly declared default constructor because you define Vect::Vect(int n). Hence the line Vect c; cannot compile.
The code c = a does not call your copy constructor Vect::Vect(const Vect& original), because the variable c already exists (assuming you have fixed the problem above). It does, instead, call the implicitly defined copy assignment operator, which you have not explicitly defined. This however just copies the member variables, thus it does not have the "right" logic since, after such a copy, both c.data and a.data point to the same area of memory. They are not a "copy", and so when a and c go out of scope, the allocated memory is freed twice (crashing the program).
You need to define a correct copy-assignment operator Vect::operator=.
Other points:
Do not use using namespace std
Do not include <bits/stdc++.h>
I tried to initiallize my own int array's class but somthing in the operator overloading isnt working, for somereason my object's d'tor is being called before I want it to and it makes my code crash:
#include "stdafx.h"
#include "Array.h"
int _tmain(int argc, _TCHAR* argv[])
{
Array arr(6);
arr[3] = 6; //code crashes here
printf("%d\n", arr[0]);
return 0;
}
and now the class:
header file:
#pragma once
#include <malloc.h>
class Array
{
public:
//ctor dtor and operator overloading
Array(int);
Array(int *, int);
~Array();
Array operator[](int i);
//here memebers are defined
int *arr;
int size;
};
----cpp file---
#include "stdafx.h"
#include "Array.h"
//the function mallocs size for the array.
Array::Array(int g = 1) :size(g) //diplomatic value for size =1
{
this->arr = (int*)malloc(sizeof(int) * this->size);
}
Array::Array(int *p, int m_size=1) :arr(p), size(m_size)
{}
Array::~Array()
{
delete arr;
}
after this function my object is being deleted by the d'tor
Array Array::operator[] (int i){
for (int j=0; j < i; ++j)
{
++(this->arr);
}
return *this;
}
Because the operator[] function returns an Array object by value. That means when you do your assignment arr[3] = 6 the operator returns a copy of this, the compiler then implicitly creates an array object from the integer 6 (because it has a matching constructor) and suddenly your assignment looks like
arr[3] = Array(6);
Somewhere the temporary array objects (the one returned by the operator[] function, and the one the compiler creates on the right-hand side of the assignment) have to be destructed, but by then you have multiple object all using the same pointer arr inside themselves. The first temporary object is destructed and it deletes the pointer, leaving all other objects with an invalid pointer. Then the next temporary object is destructed and tries to delete the now invalid pointer. Boom, you have a crash.
There are two things you need to do to fix the problem. The first is to realize that the operator[] function returns the wrong type, it should return a reference to an element of the contained array instead:
int& Array::operator[](size_t const i)
{
return arr[i];
}
The second thing you need to do is to read about the rules of three, five and zero.
Also, to prevent the compiler from mistakenly construct an object from an int value, you should mark the constructor as explicit:
explicit Array(int);
The main problem
Regardless of other problems in your code, the signature of your operator[] is wrong:
Array Array::operator[] (int i){
...
}
You don't return an element of the array here ! You return a whole new array instead. So in your faulty statement, a new temporary Array gets constructed and gets destructed at the end of the enclosing expression.
Try this instead. At least it will not crash immediately:
int& Array::operator[] (int i){
return arr[i];
}
The cause of the crash
Unfortunately, you allocate arr using malloc(). Never do this in C++ but use new[] instead. This would not lead to a crash by itself. But in addition in your destructor you use delete.
It's either malloc()/free() or new/delete or new[]/delete[] Any other combination is undefined behavior (this causes the crash in your original code, when the temporary Array got destroyed).
Correct the problem as follows:
Array::Array(int g = 1) :size(g) //diplomatic value for size =1
{
arr = new int[size];
}
Array::~Array()
{
delete[] arr;
}
It will compile and work: online demo
Other serious issue
Finally to make the things even worse, your original indexing operator returns *this, making so a clone of your existing Array. This is now solved. But if you'd make any copy of your Array you'd have another problem:
This will cause the arr pointer to be used in two places. The first Array that gests destructed will invalidate the arr pointer that is used in the original Array. Any subsequent dereferencing of its arr would be undefined behavior.
It's not solved in my online demo, so I I'd strongly suggest to read about the rule of 3
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.
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).