Copy constructor does not work and causes memory leak - c++

For my own created Vector class:
class Vector
{
private:
double* elem;
int n;
public:
Vector();
Vector(const int s);
Vector(Vector&);
~Vector();
void print();
void set(const int, const double);
double get(const int) const;
int size() const;
double norm() const;
Vector add(const Vector&) const;
Vector subtract(const Vector&) const;
double scalar(const Vector&) const;
};
When I try to call the copy constructor:
Vector::Vector(Vector& x)
{
int count = 0;
n = x.n;
elem = new double[n];
while (count < n)
{
elem[n] = x.elem[n];
count++;
}
}
It copies the address instead of the elements of the vector. Does anybody have an idea why this happen?
P.S. I In the destructor I have written
delete []elem;

Because
Vector(Vector&);
it is not signature for a copy constructor. Right signature would be
Vector(const Vector&);
Compiler doesn't see user defined copy constructor and silently generates it's own default copy constructor which just make copy of
double* elem;
int n;
and doesn't care about allocation new memory and copying elements of array.

Vector::Vector(Vector& x)
{
int count = 0;
n = x.n;
elem = new double[n];
while (count < n)
{
elem[n] = x.elem[n];//here should be:elem[count] = x.elem[count]
count++;
}
}

Related

operator overloading opertator + cant convert from pointer to const

i have a sparse matrix that is created with two arrays and each array index have a linked list the non zero numbers are in there including the i and j indexs
the header
class MNode {
public:
double _data;
int _indexI, _indexJ; // the place of the node in the matrix
// clarification: _nextRow is a pointer to the next columns in the row
MNode* _nextRow, *_nextCol;
MNode(double data, int i, int j);
};
private:
string _type;
MNode** _rowHead, **_colHead;
int _rowSize, _colSize;
int _elemNum;
void setValue(int, int, double);
void removeElement(int, int);
void insertNode(MNode*);
bool IsExist(int, int);
void setElementByType(int i, int j, double data);
public:
// construct a 'rows X cols' matrix.
SMatrix(int rows, int cols,string type);
// set the (i,j) element to be 'data'
void setElement(int i, int j, double data);
// destroy this matrix.
~SMatrix();
double getElement(int, int);
friend std::ostream& operator<<(std::ostream& os, const SMatrix& mat);
SMatrix& operator = (const SMatrix& other);
SMatrix & operator+(const SMatrix & other) const;
};
the cpp here is the overloading + function i get an erorr
cannot convert this pointer to const SMatrix to Smatrix&
SMatrix &SMatrix::operator +(const SMatrix& other) const {
SMatrix temp(3, 3, "any") ;
if (other._rowSize == this->_rowSize&&other._colSize == this->_colSize&&other._type == this->_type) {
for (int j = 0; j < other._colSize; j++) {
for (int i = 0; i < other._rowSize; i++) {
temp.setElement(i, j, (other.getElement(i, j) + this->getElement(i, j)));
}
}
}
return temp;
}
here is the contructor
SMatrix::SMatrix(int rows, int cols,string matType )
{
_type = matType;
_rowSize = rows;
_colSize = cols;
_elemNum = 0;
_rowHead = new MNode*[rows];
if (!_rowHead)
{
cout << "allocation error";
exit(1);
}
_colHead = new MNode*[cols];
if (!_colHead)
{
cout << "allocation error";
exit(1);
}
for (int i = 0; i < rows; i++)
{
_rowHead[i] = NULL;
}
for (int i = 0; i < cols; i++)
{
_colHead[i] = NULL;
}
}
iam not sure what i need to do the signature of the function is given and cant be chanbged any idea?
You've declared other to be a reference to const:
SMatrix & operator+(const SMatrix & other) const;
^^^^^
You call the member function getElement on that reference:
temp.setElement(i, j, (other.getElement(i, j) + this->getElement(i, j)));
^^^^^^^^^^^^^^^^
You've declared getElement to be non-const:
double getElement(int, int);
^
You may only call const member functions on const references.
the signature of the function is given and cant be chanbged any idea?
If the signature of getElement can't be changed, then you've been dealt a badly written signature. There should be no good reason why a getter couldn't be const. That said, since you're within the class, you can access all members directly without using a getter.
There's another bug. You've declared operator+ to return a reference.
SMatrix &SMatrix::operator +(const SMatrix& other) const
^
But you return a local automatic variable temp:
SMatrix temp(3, 3, "any") ;
// ...
return temp;
Automatic variables are destroyed at the end of the function. Therefore the returned reference will always be dangling and any use of it would have undefined behaviour.
the signature of the function is given and cant be chanbged any idea?
If the signature of operator+ can't be changed, then you've been dealt a badly written signature. The function really should return by value. There's no sensible solution that could return a reference. Using a static local would technically work, but that has some limitations on usage that aren't apparent from the interface.

Operator overloading as friend function error

I'm trying to use + to add 2 vector (mathematical vector). Here's my code:
class Vector{
double v[Max_size];
int dim;
public:
int getDim() const;
Vector();
Vector(int n);
Vector(const Vector& a);
Vector add(const Vector&b);
friend Vector operator+(Vector summand1, Vector summand2);
};
Operator overloading:
Vector operator+(Vector summand1, Vector summand2){
int dim1 = summand1.getDim();
int dim2 = summand2.getDim();
assert(dim1 == dim2);
Vector sum(dim1);
int i;
for(i = 0; i < dim1; i++){
sum.v[i] = summand1.v[i] + summand2.v[i];
}
return sum;
}
And how I use it:
Vector m = v+t;
When I run the code, it always shows that m is (0,0) (2D vector), which is the default value generated by the constructor. What's wrong with it? Thanks!
Your copy constructor:
Vector::Vector(const Vector& a){
dim = a.dim;
Vector(dim);
}
correctly sets the value of the dim member, but has not other side effect.
You should have a variant of the following code:
Vector::Vector(const Vector& a) : dim(a.dim) {
std::copy(std::begin(a.v), std::end(a.v), v);
}
This will actually copy the data present in the parameter, and you will see the correct behavior for the code:
// Copy constructor called here, but did not correctly copy the data before.
Vector m = v + t;
For a better (by that I intend simpler and safer) Vector class, if you have access to a compiler that is at least C++11 compliant, you can write:
class Vector{
std::array<double, Max_size> v; // Note the std::array here.
int dim;
public:
int getDim() const;
Vector();
Vector(int n);
Vector(const Vector& a);
Vector add(const Vector&b);
friend Vector operator+(Vector summand1, Vector summand2);
};
The std::array will take care of everything, provided you write your copy constructor like this:
Vector::Vector(const Vector& a) : v(a.v), dim(a.dim) {
}
Or, even better, you could then let the compiler generate the copy constructor itself, with the same behavior.

C++:copy constructor

I have a problem with my program in c++. I try to write copy constructor. Everything is good until I start copying elements from array from object that is applied as a reference.
I can print every element of applied array but I can't copy it to array in object that copy constructor will create.
Here's the code (I show only the header file and some methods that needs copy constuctor because all code is too long I think)
Header.h
#pragma once
# include <iostream>
# include <fstream>
# include <cmath>
using namespace std;
class Polynomial {
private:
int degree;
double* coefficients;
public:
static const string errors[5];
Polynomial(const Polynomial& wzor); // konstruktor kopiujacy
Polynomial(float n);
~Polynomial();
void setCoefficient(unsigned int i, double value);
double getCoefficient(unsigned int i);
double value(double x);
friend ostream & operator <<(ostream & out, Polynomial & p);
double operator[](const int index);
double operator()(double x);
void operator=(Polynomial &obiekt);
friend Polynomial operator+(Polynomial &obiekt,Polynomial &obiekt1);
friend Polynomial operator-(Polynomial &obiekt,Polynomial &obiekt1);
friend Polynomial operator~(Polynomial &obiekt);
friend Polynomial operator*(Polynomial &obiekt,Polynomial &obiekt1);
friend Polynomial operator*(Polynomial &obiekt,double x);
};
Polynomial::Polynomial(float n) {
if(n<0){
throw 0;
}
else if(floor(n)-n != 0){
throw 2;
}
degree=(int)n;
coefficients=new double [(int)n+1];
for(unsigned int i=0; i<n; i++) {
coefficients[i]=0.0;
}
coefficients[(int)n]=1.0;
}
Polynomial::Polynomial(const Polynomial &wzor){
degree=wzor.degree; // it's allright
for(int i=0; i<=wzor.degree; i++){
coefficients[i]=wzor.coefficients[i]; // compilator says that this line is wrong
}
}
Polynomial::~Polynomial(){
delete coefficients;
}
Polynomial operator+(Polynomial &obiekt,Polynomial &obiekt1){
Polynomial nowy(1);
if(obiekt1.degree > obiekt.degree){
nowy=obiekt1;
for(int i=0; i<=obiekt.degree; i++){
nowy.coefficients[i]=nowy.coefficients[i]+obiekt.coefficients[i];
}
}
else{
nowy=obiekt;
for(int i=0; i<=obiekt1.degree; i++){
nowy.coefficients[i]=nowy.coefficients[i]+obiekt1.coefficients[i];
}
}
return nowy;
}
class Polynomial {
private:
int degree;
double* coefficients; // Pointer to double
/* ... */
}
You have declared coefficients to be a pointer to double, not an array.
for(int i = 0; i <= wzor.degree; i++) {
coefficients[i] = wzor.coefficients[i]; // Error! No memory allocated.
}
Here you are trying to assign values to memory that doesn't exist. You need to allocate the array before you can assign element data to it. Also you should initialize members in the initialization list instead of the ctor body. Try something like this instead:
Polynomial::Polynomial(const Polynomial& wzor)
: degree(wzor.degree), coefficients(new double[wzor.degree + 1]) { // Init
for (int i=0;i<=wzor.degree;i++) {
coefficients[i]=wzor.coefficients[i];
}
}
Remember that the copy constructor is a constructor. It will construct a new instance of the object and you need to allocate new memory for the new copy.
Also in your destructor you must use delete[] instead of delete as you are deleting an array.
The assignment operator should be declared as:
Polynomial& operator= (const Polynomial& obiekt);
You should use type std::size_t for variables storing array indexes instead of int.
Finally I recommend using containers from the standard library instead of built in arrays, e.g. std::vector.
#include <vector>
std::vector<double> coefficients;
you can use the copy of the vector which means you do not have to implement it on your own.
And you do not have to do the delete stuff.
Use resize & [] or push_back methods to work on the string. Your degree will be coefficients.size().
You're assignment operator is wrong. It should be
Polynomial & operator=(const Polynomial &obiekt);

templated code not working while non-templated code works!

I spent several hours, completely stuck when I realized that only the templated version of my code has a bug.
In the following code, when pushing_back elements in the myMap, the original vectors myVec1 and myVec2 are modified and contain garbage at the end of the execution. If I un-template everything, just replacing template<T> by double, then the code works fine as I would expect (the original arrays are untouched).
The funny thing is if I put a cout in the copy constructor, it does not get called if the code is templated. But it gets called if I replace the copy constructor with Vector<T2> by the original type Vector<T>, and then everything work fine.
Why wouldn't the compiler know that T2==T since I only use double?
(note, the code has been made as short as possible so as to show the errors - I thus removed accessors, made everything public etc.).
#include <vector>
#include <map>
template<class T>
class Vector{
public:
Vector():n(0),data(0){};
Vector(int N):n(N),data(new T[N]){};
Vector(T x, T y):n(2),data(new T[2]){data[0]=x; data[1]=y;};
template<class T2> Vector(const Vector<T2>& rhs):n(rhs.n), data(new T[n])
{
for (int i=0; i<n; i++)
data[i] = T(rhs.data[i]);
}
~Vector(){delete[] data;}
Vector& operator=(const Vector& rhs)
{
if (rhs.n != n)
{
if (data)
delete[] data;
data = new T[rhs.n];
}
n = rhs.n;
memcpy(data, rhs.data, n*sizeof(T));
return *this;
}
T& operator[](int i){return data[i];}
const T& operator[](int i) const {return data[i];}
int n;
T* data;
};
typedef Vector<double> Vectord;
template <class T> inline bool operator<(const Vector<T>& v1, const Vector<T>& v2)
{
for (int i=0; i<v1.n; i++)
{
if (v1[i]<v2[i]) return true;
if (v1[i]>v2[i]) return false;
}
return false;
}
int main(int argc, char** argv)
{
std::vector<Vectord> myVec1(3);
myVec1[0] = Vectord(1.,3.);
myVec1[1] = Vectord(3.,3.);
myVec1[2] = Vectord(1.,5.);
std::vector<Vectord> myVec2(3);
myVec2[0] = Vectord(4.,1.);
myVec2[1] = Vectord(2.,5.);
myVec2[2] = Vectord(6.,5.);
std::map<Vectord, std::vector<Vectord> > myMap;
for (int i=0; i<3; i++)
{
myMap[myVec1[i]].push_back(myVec2[i]);
}
return 0;
}
A templated constructor is never a copy constructor.
So your class is using the automatically generated copy constructor.
Cheers & hth.,

Returning deep copies of objects when overloading the = operator

So I making a container class for integers and I want to overload the = operator so that I can return a deep copy of the object. My code works but the two objects point to the same address. This is the main.cpp file:
int main (int argc, const char * argv[]) {
IntList cArray(5);
for (int i = 0; i < cArray.getLength(); i++) {
cArray[i] = (i + 1) * 10;
}
using namespace std;
for (int i = 0; i < cArray.getLength(); i++)
cout << cArray[i] << " ";
cout << endl << popped << endl;
IntList cArray2(4);
for (int i = 0; i < cArray2.getLength(); i++)
cArray2[i] = i * 5;
cArray2 = cArray;
cArray2[2] = 1000;
for (int i = 0; i < cArray.getLength(); i++)
cout << cArray[i] << " ";
cout << endl;
for (int i = 0; i < cArray2.getLength(); i++)
cout << cArray2[i] << " ";
cout << endl;
return 0;
}
This is the header file for the IntList class:
class IntList {
private:
int _length;
int* _data;
public:
IntList(int length);
~IntList();
void erase();
void reallocate(int length); // Faster way to call erase() and resize()
void resize(int length);
void insert(int value, int index);
void prepend(int value);
void append(int value);
int pop(int index);
void removeBefore(int index); // Exclusive
void removeAfter(int index); // Exclusive
int getLength();
int indexOf(int value);
int& operator[](int index);
IntList operator=(IntList* source);
};
And this is the implementation of IntClass's operator=() method:
IntList IntList::operator=(IntList* source) {
_length = source->getLength();
reallocate(_length);
for (int i = 0; i < _length; i++) {
_data[i] = (*source)[i];
}
return *this;
}
You're not working with pointers to IntList - operator= typically takes a const & and returns a reference to the instance being assigned to.
IntList & IntList::operator=(IntList const & source) {
...
return *this;
}
Remember that you also need a copy constructor: IntList(IntList const & source)
You can make an operator= which takes a pointer to IntList - that would only work if you did something like this:
IntList l1;
IntList l2;
l1 = &l2;
This isn't typical usage, and you should rather be explicit if you require this, use e.g. void IntList::copyFrom(IntList const *) in this case.
Other changes you should make:
Add this:
int operator[](int index) const;
Make these const:
int getLength() const;
int indexOf(int value) const;
Because your assignment operator takes a pointer to an IntList, you would need to call it like this:
cArray2 = &cArray;
Your example code is using the default assignment operator generated by your compiler. Your assignment operator should have this declaration instead:
IntList& IntList::operator=(IntList const& source)
IntList IntList::operator=(IntList* source)
Wrong signature for operator=, as it's parameter type is a pointer to IntList
Correct signature is this:
IntList & IntList::operator=(const IntList & source) //reference of source!
//^^^ note this ^^^ note this as well!
That is, make both parameter type as well as return type reference.
Your operator needs the signature IntList& operator=(const IntList& source);. Note the reference instead of the pointer, and that you must RETURN by reference as well to allow assignment chaining. When you pass it by pointer anywhere implicit assignment is required the compiler-generated shallow copy assignment operator will be used.
EDIT: You also need to make getLength const so that it's able to be called inside the assignment operator.