I am receiving a runtime error from code I have written. When I call the grow() function it works perfectly until it hits the delete, then it crashes and says:
This really confuses me and I do not understand what is going on with that.
Here is my code where it is happening:
The .cpp File
#include "MyVector.h"
#include <cstdlib>;
void MyVector::grow()
{
if (cap == 0)
cap = MINCAP;
else
cap = cap*MINCAP;
int* temp = new int[cap];
for (int i = 0; i < vectorSize; i++)
{
temp [i] = theVector[i];
}
for (int i = vectorSize; i < cap; i++)
{
temp[i] = 0;
}
delete[] theVector;
theVector = temp;
}
MyVector::MyVector()
{
clear();
}
MyVector::~MyVector()
{
delete[] this->theVector;
}
MyVector::MyVector(int _cap)
{
cap = _cap;
for (int i = 0; i < cap; i++)
{
this->theVector[i] = 0;
}
}
MyVector::MyVector(const MyVector & vect)
{
this->vectorSize = vect.vectorSize;
this->cap = vect.cap;
delete[] theVector;
theVector = new int[cap];
for (int i = 0; i < vectorSize; i++)
{
this->theVector[i] = vect.theVector[i];
}
for (int i = vectorSize; i < cap; i++)
{
this->theVector[i] = 0;
}
}
int MyVector::size() const
{
return vectorSize;
}
int MyVector::capacity() const
{
return cap;
}
void MyVector::clear()
{
vectorSize = 0;
cap = MINCAP;
delete[] theVector;
theVector = new int[MINCAP];
for (int i = 0; i <MINCAP; i++)
{
*(theVector + i) = 0;
}
}
//Put an int into the vector
void MyVector::push_back(int n)
{
if (theVector == nullptr)
clear();
if (vectorSize+1 >= cap)
{
grow();
theVector[vectorSize] = n;
vectorSize++;
}
else
{
theVector[vectorSize] = n;
vectorSize++;
}
}
int MyVector::at(int _location)
{
if (_location < 0 || _location >= vectorSize)
throw _location;
return theVector[_location];
}
MyVector & MyVector::operator=(const MyVector & rho)
{
// test for self assignment
if (this == &rho)
return *this;
// clean up array in left hand object (this)
delete[] this->theVector;
// create a new array big enough to hold right hand object's data
this->vectorSize = rho.size();
this->cap = rho.cap;
this->theVector = new int[cap];
// copy the data
for (int i = 0; i < vectorSize; i++)
{
this->theVector[i] = rho.theVector[i];
}
for (int i = vectorSize; i < cap; i++)
{
this->theVector[i] = 0;
}
// return this object
return *this;
}
The.h File
#pragma once
#include <array>
#include <fstream>
using namespace std;
class MyVector
{
private:
//the minimum capacity of the vector
const int MINCAP = 2;
//the amount of items in the vector
int vectorSize = 0;
//the maximum ammount of items in the vector
int cap = MINCAP;
//The pointer to the first integer in the vector
int* theVector = new int[MINCAP];
//The grow function
//Parameters : none
//returns : none
void grow();
public:
//The nonparmeterized constructor
//Parameters : none
//returns :none
MyVector();
//The deconstructor
//Parameters : none
//returns : none
~MyVector();
// The parameterized constructor
//Parameters : the capacity to set it to
//returns : none
MyVector(int _cap);
//Get the size
//Parameters : none
//returns : the size
MyVector(const MyVector& vect);
//Get the size
//Parameters : none
//returns : the size
int size() const;
//get the capacity
//Parameters : none
//returns : cap
int capacity() const;
//clear the data
//Parameters : none
//returns :none
void clear();
//insert an int into the vector
//Parameters : the int
//returns : none
void push_back(int n);
//gets the int at a location
//Parameters : the location
//returns : the integer
int at(int _location);
//Overload the = operator
//Parameters : the one to copy
//returns : the vector
MyVector& operator=(const MyVector& rho);
//Overload the << operator
//Parameters : the one to copy
//returns : the vector
friend ostream& operator<<(ostream& os, MyVector& TheVector)
{
for (int i = 0; i < TheVector.size(); i++)
{
os << TheVector.at(i) << ", ";
}
return os;
}
};
The driver to test it.
#include <iostream>
#include "MyVector.h"
using namespace std;
// the printV function
// used to test the copy constructor
// parameter: a MyVector object
void printV(MyVector);
int main()
{
cout << "\nCreating a vector Sam of size 4.";
MyVector sam(4);
cout << "\nPush 12 values into the vector.";
for (int i = 0; i < 12; i++)
sam.push_back(i);
cout << "\nHere is sam: ";
cout << sam;
cout << "\n---------------\n";
cout << "\nCreating a vector Joe of size 4.";
MyVector joe(4);
cout << "\nPush 6 values into the vector.";
for (int i = 0; i < 6; i++)
joe.push_back(i * 3);
cout << "\nHere is joe: ";
cout << joe;
cout << "\n---------------\n";
cout << "\nTest the overloaded assignment operator \"joe = sam\": ";
joe = sam;
cout << "\nHere is sam: ";
cout << sam;
cout << "\n---------------\n";
cout << "\nHere is joe: ";
cout << joe;
cout << "\n---------------\n";
// pass a copy of sam by value
printV(sam);
cout << endl;
system("PAUSE");
return 0;
}
void printV(MyVector v)
{
cout << "\n--------------------\n";
cout << "Printing a copy of a vector\n";
cout << v;
}
EDIT: I updated the code with the recommendations.
There are a few problems with your code:
your MyVector(int) constructor does not allocate the requested number of array elements. It is not even touching theVector at all, so theVector is being member-initialized to the default of MINCAP elements, even if the requested cap is actually higher.
your MyVector(MyVector&) copy constructor is declared wrong. To be a proper copy constructor, it needs to take the input object by const reference instead. Without that, you do not have a proper copy constructor. If the compiler generates its own default copy constructor, it will simply copy your theVector pointer from one object to another and not actually make a new copy of the array data, thus causing ownership problems.
case in point, your printV() function takes an input MyVector by value, which copy-constructs a temporary object. When the temporary goes out of scope and calls delete[] on its theVector pointer, it is actually going to destroy the array in the original MyVector object if the compiler's default copy constructor is used. You need a proper copy constructor.
clear() is using delete instead of delete[]. Memory allocated with new must be freed with delete. Memory allocated with new[] must be freed with delete[]. Mismatching them can cause memory problems.
With that said, I would suggest the following implementation:
#pragma once
#include <iostream>
class MyVector
{
private:
//the minimum capacity of the vector
const int MINCAP = 2;
//the number of items in the vector
int vectorSize = 0;
//the maximum number of items in the vector
int cap = 0;
//The pointer to the first integer in the vector
int* theVector = nullptr;
//The grow function
//Parameters : none
//returns : none
void grow();
public:
//The nonparmeterized constructor
//Parameters : none
//returns :none
MyVector();
// The parameterized constructor
//Parameters : the capacity to set it to
//returns : none
MyVector(int _cap);
// The copy constructor
//Parameters : the vector to copy from
//returns : none
MyVector(const MyVector& src);
// The move constructor
//Parameters : the vector to move from
//returns : none
MyVector(MyVector&& src);
//The destructor
//Parameters : none
//returns : none
~MyVector();
//Get the size
//Parameters : none
//returns : the size
int size() const;
//get the capacity
//Parameters : none
//returns : cap
int capacity() const;
//clear the data
//Parameters : none
//returns :none
void clear();
//insert an int into the vector
//Parameters : the int
//returns : none
void push_back(int n);
//gets the int at a location
//Parameters : the location
//returns : the integer
int at(int _location);
//swap the content of a vector with another
//Parameters : the vector to swap with
//returns : none
void swap(MyVector& other);
//Overload the copy = operator
//Parameters : the one to copy from
//returns : the vector
MyVector& operator=(const MyVector &rho);
//Overload the move = operator
//Parameters : the one to move from
//returns : the vector
MyVector& operator=(MyVector && rho);
//Overload the << operator
//Parameters : the one to print
//returns : the stream
friend std::ostream& operator<<(std::ostream& os, const MyVector& rho);
};
std::ostream& operator<<(std::ostream& os, const MyVector& rho);
void swap(MyVector &v1, MyVector &v2) { v1.swap(v2); }
namespace std {
template <>
void swap(MyVector &v1, MyVector &v2)
{
v1.swap(v2);
}
}
#include "MyVector.h"
#include <algorithm>
#include <utility>
MyVector::MyVector()
: MyVector(MINCAP)
{
}
MyVector::MyVector(int _cap)
: theVector(new int[_cap]), cap(_cap)
{
std::fill_n(theVector, cap, 0);
}
MyVector::MyVector(const MyVector & src)
: theVector(new int[src.cap]), cap(src.cap), vectorSize(src.vectorSize)
{
std::copy_n(src.theVector, vectorSize, theVector);
std::fill_n(theVector+vectorSize, cap-vectorSize, 0);
}
MyVector::MyVector(MyVector && src)
{
src.swap(*this);
}
MyVector::~MyVector()
{
delete[] theVector;
}
void MyVector::grow()
{
int newcap = cap;
if (newcap == 0)
newcap = MINCAP;
else
newcap = newcap * MINCAP;
int* newVector = new int[newcap];
std::copy_n(theVector, vectorSize, newVector);
std::fill_n(newVector+vectorSize, newcap-vectorSize, 0);
delete[] theVector;
theVector = newVector;
cap = newcap;
}
int MyVector::size() const
{
return vectorSize;
}
int MyVector::capacity() const
{
return cap;
}
void MyVector::clear()
{
*this = MyVector();
}
void MyVector::push_back(int n)
{
if (vectorSize >= cap)
grow();
theVector[vectorSize] = n;
++vectorSize;
}
int MyVector::at(int _location)
{
if ((_location < 0) || (_location >= vectorSize))
throw _location;
return theVector[_location];
}
void MyVector::swap(MyVector& other)
{
std::swap(theVector, other.theVector);
std::swap(cap, other.cap);
std::swap(vectorSize, other.vectorSize);
}
MyVector& MyVector::operator=(const MyVector &rho)
{
if (this != &rho)
{
int newcap = rho.cap;
if (cap != newcap)
{
delete[] theVector;
theVector = nullptr;
cap = 0;
vectorSize = 0;
theVector = new int[newcap];
cap = newcap;
}
int newsize = rho.vectorSize;
std::copy_n(rho.theVector, newsize, theVector);
std::fill_n(theVector+newsize, cap-newsize, 0);
vectorSize = newsize;
}
return *this;
}
MyVector& MyVector::operator=(MyVector && rho)
{
rho.swap(*this);
return *this;
}
std::ostream& operator<<(std::ostream& os, const MyVector& rho)
{
os << "size " << rho.vectorSize << ", capacity " << rho.cap;
if (rho.vectorSize > 0)
{
os << "\n" << rho.theVector[0];
for (int i = 1; i < rho.vectorSize; ++i)
{
os << ", " << rho.theVector[i];
}
}
return os;
}
#include <iostream>
#include "MyVector.h"
// the printV function
// used to test the copy constructor
// parameter: a MyVector object
void printV(MyVector);
int main()
{
std::cout << "\nCreating a vector Sam of capacity 4.";
MyVector sam(4);
std::cout << "\nPush 12 values into the vector.";
for (int i = 0; i < 12; ++i)
sam.push_back(i);
std::cout << "\nHere is sam: ";
std::cout << sam;
std::cout << "\n---------------\n";
std::cout << "\nCreating a vector Joe of capacity 4.";
MyVector joe(4);
std::cout << "\nPush 6 values into the vector.";
for (int i = 0; i < 6; ++i)
joe.push_back(i * 3);
std::cout << "\nHere is joe: ";
std::cout << joe;
std::cout << "\n---------------\n";
std::cout << "\nTest the overloaded copy assignment operator \"joe = sam\": ";
joe = sam;
std::cout << "\nHere is sam: ";
std::cout << sam;
std::cout << "\n---------------\n";
std::cout << "\nHere is joe: ";
std::cout << joe;
std::cout << "\n---------------\n";
std::cout << "\nTest the overloaded move assignment operator \"joe = MyVector(5)\": ";
joe = MyVector(5);
std::cout << "\nHere is joe: ";
std::cout << joe;
std::cout << "\n---------------\n";
// pass a copy of sam by value
printV(sam);
std::cout << std::endl;
system("PAUSE");
return 0;
}
void printV(MyVector v)
{
cout << "\n--------------------\n";
cout << "Printing a copy of a vector\n";
cout << v;
}
Related
I have a class strings:
class strings
{
protected:
string *ptr;
int size;
public:
strings() {
ptr = NULL;
size = -1;
}
strings(int size) {
this->size = size;
ptr = new string[size];
}
string* retPtr() {
return ptr;
}
void setPtr(int size)
{
ptr = new string[size];
this->size = size;
}
strings(const strings& obj) {
this->size = obj.size;
for (int i = 0;i < size;++i)
this->ptr[i] = obj.ptr[i];
}
friend istream& operator>>(istream& input, strings& obj) {
cin.ignore();
cout << "Enter " << obj.size << " string one by one:\n";
for (int i = 0;i < obj.size;++i)
{
getline(input, obj.ptr[i]);
}
return input;
}
friend ostream& operator<<(ostream& output, const strings& obj) {
cout << "Strings are:\n";
for (int i = 0;i < obj.size;++i)
output << obj.ptr[i] << "\n";
return output;
}
void operator =(const strings& obj)
{
this->size = obj.size;
for (int i = 0;i < size;++i)
ptr[i] = obj.ptr[i];
}
~strings()
{
delete[]ptr;
}
};
Another class stringsFromNumbers:
class stringsFromNumbers:public strings
{
int numbers;
public:
stringsFromNumbers(){
numbers = -1;
}
stringsFromNumbers(int size, int numbers):strings(size){
this->numbers = numbers;
}
stringsFromNumbers(const stringsFromNumbers& obj)
{
this->numbers = obj.numbers;
this->size = obj.size;
for (int i = 0;i < size;++i)
this->ptr[i] = obj.ptr[i];
}
friend istream& operator>>(istream& input, stringsFromNumbers& obj) {
cin.ignore();
cout << "Enter " << obj.size << " string one by one:\n";
for (int i = 0;i < obj.size;++i)
{
getline(cin, obj.ptr[i]);
}
return input;
}
friend ostream& operator<<(ostream& output, const stringsFromNumbers& obj) {
cout << "Numbers are: " << obj.numbers;
cout << "\nStrings are:\n";
for (int i = 0;i < obj.size;++i)
output << obj.ptr[i] << "\n";
return output;
}
void operator =(const stringsFromNumbers& obj)
{
this->numbers = obj.numbers;
this->size = obj.size;
for (int i = 0;i < size;++i)
this->ptr[i] = obj.ptr[i];
}
~stringsFromNumbers()
{
delete[] ptr;
}
};
Whenever i try execute this line of code:
stringsFromNumbers obj2(N, P);
where N and P are valid integers, I get an "Access Reading Violation", do you see something wrong in the code?
I have been stuck on this for almost 2 hours. I have tried debugging and fixing it, i have also tried multiple other methods. The exception takes me to this function:
inline void _Container_base12::_Orphan_all() noexcept {
#if _ITERATOR_DEBUG_LEVEL == 2
if (_Myproxy) { // proxy allocated, drain it
_Lockit _Lock(_LOCK_DEBUG);
for (auto _Pnext = &_Myproxy->_Myfirstiter; *_Pnext; *_Pnext = (*_Pnext)->_Mynextiter) {
(*_Pnext)->_Myproxy = nullptr;
}
_Myproxy->_Myfirstiter = nullptr;
}
#endif // _ITERATOR_DEBUG_LEVEL == 2
}
The problem is with this function most probably but how can it be fixed?
stringsFromNumbers(int size, int numbers):strings(size){
this->numbers = numbers;
}
Both stringsFromNumbers::~stringsFromNumbers and strings::strings call delete[] on ptr, so the array is attempted to be freed twice; the second time causes an issue.
Only one of these classes should be responsible for managing the lifecycle of ptr. Remove the delete[] from stringsFromNumbers::~stringsFromNumbers.
If in some other case you've got a valid reason to free the array in the destructor of a subclass, make sure the parent class destructor is able to deal with the new state (e.g. by setting ptr to nullptr after deleting it), but in general you should avoid the complexity of making both classes sharing responsibility for freeing the memory.
I made a dynamic array with template. The problem is that when I don't keep there pointers (for example: Tab<string> da;) my destructor doesn't have to clear it and throws error caused by delete arr[i];. My question is if I can put some if condition(in which I would put clear() method) which would tell me if my array keeps pointers. In the simplest way I can use clear() in main when I keeps there pointers, but my teacher wants me to make it like I wrote above.
I tried using is_pointer, but it doesn't work or I use it wrong.
Any suggestions?
#ifndef TABLICA_H
#define TABLICA_H
#include <iostream>
#include <type_traits>
using namespace std;
template<class T>
class Tab
{
public:
int size = 0;
int max_size = 1;
T* arr;
bool isDynamic = false;
Tab()
{
arr = new T[max_size];
}
~Tab()
{
clear();
delete[] arr;
}
void check_size()
{
if (size == max_size)
{
max_size = max_size * 2;
T* arr2 = new T[max_size];
for (int i = 0; i < size; i++)
{
arr2[i] = arr[i];
}
delete[] arr;
arr = arr2;
}
}
void push_back(const T& value)
{
check_size();
arr[size] = value;
size++;
}
T return_by_index(int index)
{
if (index<0 || index > size)
{
return NULL;
}
return arr[index];
}
bool replace(int index, const T& value)
{
if (index<0 || index > size)
{
return false;
}
arr[index] = value;
return true;
}
void print(int number)
{
cout << "Rozmiar obecny: " << size << endl;
cout << "Rozmiar maksymalny: " << max_size << endl;
cout << "Adres tablicy: " << arr << endl;
cout << "Kilka poczatkowych elementow tablicy " << "(" << number << ")" << endl;
for (int i = 0; i < number; i++)
{
cout << *arr[i] << endl;
}
}
void clear()
{
for (int i = 0; i < size; i++)
{
delete arr[i];
}
}
};
#endif
//Source:
#include <iostream>
struct object
{
int field1;
char field2;
object()
{
field1 = rand() % 10001;
field2 = rand() % 26 + 'A';
}
};
ostream& operator<<(ostream& out, const object& o)
{
return out << o.field1 << " " << o.field2;
}
int main()
{
Tab < object* >* da = new Tab < object* >();
delete da;
system("PAUSE");
return 0;
I'm trying to write code that implemets a template for a matrix with boundary check and additional operators. However, I'm stuck at a SIGGSEGV right now.
The matrix is based on a vector class I wrote myself, too:
#ifndef VEKTOR_H
#define VEKTOR_H
#include "Exeptions.h"
template<typename T>
class vektor
{
private:
unsigned int length;
T* items;
public:
inline unsigned int getLength() const{return length;};
vektor():length(0),items(nullptr)
{
//ctor
}
virtual ~vektor()
{
delete [] items;
}
vektor(const vektor& other):length(other.getLength()),items(new T[length])
{
for(int i = 0;i<length;i++)
{
items[i]=other[i];
}
}
vektor(int len):length(len),items(new T[len])
{
}
vektor<T>& operator=(const vektor& rhs)
{
if (this == &rhs) return *this; // handle self assignment
//assignment operator
length = rhs.getLength();
items = new T[length];
for(int i = 0;i<length;i++)
{
items[i]=rhs[i];
}
return *this;
}
T& operator[](const unsigned int index)const
{
if(index >= 0 && index < length)
{
return items[index];
}
else throw out_of_bounds();
}
};
#endif // VEKTOR_H
Then the code for the matrix:
#ifndef MATRIX_H
#define MATRIX_H
#include "vektor.h"
template <typename T>
class matrix
{
private:
int columns;
vektor<T>* tabs;
public:
inline int getColCount()const{return columns;};
inline int getRowCount()const{return tabs[0].getLength();};
inline vektor<T>* getTabs()const{return tabs;};
matrix():columns(0),tabs(new vektor<T>(0))
{
//ctor
}
matrix(int columns, int rows):columns(columns),tabs(new vektor<T>[columns])
{
for(int i = 0; i< columns;i++)
{
tabs[i] = *new vektor<T>(rows);
}
}
virtual ~matrix()
{
delete tabs;
}
matrix(const matrix& other):rows(other.getColCount()),tabs(new vektor<T>(*other.getTabs()))
{
//copy ctor
}
matrix<T>& operator=(const matrix& rhs)
{
if (this == &rhs) return *this; // handle self assignment
//assignment operator
spalten = rhs.getColCount();
tabs = new vektor<T>(*rhs.getTabs());
return *this;
}
vektor<T>& operator[](unsigned int index)
{
return tabs[index];
}
};
#endif // MATRIX_H
A wrapper class that instantiates a matrix with string to create a menu-like structure:
MenUI::MenUI():selectedTab(3),selectedItem(4),menItems(matrix<string>(3,4))
{
menItems[0][0] = "File";
menItems[0][1] = "Edit";
menItems[0][2] = "View";
menItems[0][3] = "Search";
menItems[1][0] = "New";
menItems[1][1] = "Undo";
menItems[1][2] = "Perspectives";
menItems[1][3] = "Find";
menItems[2][0] = "Open...";
menItems[2][1] = "Redo";
menItems[2][2] = "Toolbars";
menItems[2][3] = "Find in Files";
}
And here the SIGSEGV happens at line tmp = menItems[selectedTab][i];
void MenUI::print()
{
int offset = 0;
string tmp;
for(unsigned int i = 0; i<menItems.getColCount();i++)
{
tmp = menItems[i][0];
if (i == selectedTab) cout << "|- " << setw(10) << tmp << " -";
else cout << "| " << setw(10) << tmp << " ";
}
cout << "|" << endl;
offset = selectedTab * (10 + 5);
for(unsigned int i = 1;i<menItems.getRowCount();i++)
{
tmp = menItems[selectedTab][i];
if(i == selectedItem) cout << string(offset-3, ' ') << "|> " << setw(10) << tmp << " <|" << endl;
else cout << string(offset-3, ' ') << "| " << setw(10) << tmp << " |" << endl;
}
}
As this is the first time I used templates, I'm a bit lost right now.
I'm using Code::Blocks IDE with GCC.
It would be really great if someone could point me in the right direction.
Thanks!
If selectedTab is 3 and you do tmp = menItems[selectedTab][i]; your code will seg fault because you are accessing outside the bounds of the memory.
I might have taken what you have written too literally and you change selectedTab
For my first try with operator overloading I created a vector class and tried to sum up two vectors. My class contains an array and a vector of int that both contain the same elements.
Addition works fine with the std::vector but I encounter two issues with the array. It seems that the destructor is called at the end of the summing operation which produces a "double free or corruption" error (core dump). Plus, the first two elements of the array are always equal to zero.
Should I also overload the delete or am I missing a thing ?
The header file:
#ifndef MYVECTOR_INCLUDE
#define MYVECTOR_INCLUDE
#include <iostream>
#include <stdexcept>
#include <cstring>
#include <vector>
class MyVector {
public:
MyVector(int n);
~MyVector();
void set(int idx, int value);
int get(int idx);
void print();
MyVector &operator=(const MyVector &v);
MyVector operator+(const MyVector &v);
private:
int *data;
std::vector<int> data_vector;
int size1;
int size2;
};
#endif
The cpp file:
#include "../include/myvector.hpp"
MyVector::MyVector(int n) {
data = new int [n];
data_vector.resize(n);
size1 = n;
size2 = 1;
}
MyVector::~MyVector() {
if (data != NULL) {
delete [] data;
}
}
void MyVector::set(int idx, int value) {
data_vector[idx] = value;
data[idx] = value;
}
int MyVector::get(int idx) {
return data_vector[idx];
}
void MyVector::print() {
std::cout << "Vector data" << std::endl;
for (int i = 0; i < size1; ++i) {
std::cout << data_vector[i] << " ";
}
std::cout << std::endl;
std::cout << "Data" << std::endl;
for (int i = 0; i < size1; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
MyVector &MyVector::operator=(const MyVector &v) {
if (this == &v)
return *this;
size1 = v.size1;
size2 = v.size2;
std::copy(v.data_vector.begin(), v.data_vector.end(), data_vector.begin());
memcpy(&data, v.data, sizeof(int)*size1);
return *this;
}
MyVector MyVector::operator+(const MyVector &v) {
if ((size1 == v.size1) && (size2 == v.size2)) {
MyVector res = MyVector(size1);
for (int i = 0; i < size1; ++i) {
res.data_vector[i] = data_vector[i] + v.data_vector[i];
res.data[i] = data[i] + v.data[i];
}
return res;
}
else
throw std::length_error("Vector dimensions must agree.");
}
Thank you.
See the rule of three/five/zero.
The rule of three states
If a class requires a user-defined destructor, a user-defined copy constructor, or a user-defined copy assignment operator, it almost certainly requires all three.
In this case, you provided the destructor and copy assignment operator but forgot the copy constructor.
In operator+ you create a local object MyVector res which is later copied out and then destroyed. Since you haven't implemented a copy constructor, the default copy constructor will simply copy the original data pointer from res to another MyVector. When res is destroyed, the array pointed to by it's data member will be deleted, leaving the copied vector's data pointing to a deleted object.
I am not sure what I am doing wrong here but I used Google and found almost the identical code to mine but they did not claim an error. Our assignment is to overload the insertion operator. The problem is that I get an error in the driver for every time I pass SAM or JOE. The error states: Error 2 error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'MyVector' (or there is no acceptable conversion).
Any help is appreciated. Please note that I have not completed this assignment and if another function doesn't seem right, it may be because I haven't work on it.
Thanks in advance.
Driver.cpp
#include <iostream>
#include "MyVector.h"
using namespace std;
// the printV function
// used to test the copy constructor
// parameter: a MyVector object
void printV(MyVector);
int main()
{
cout << "\nCreating a vector Sam of size 4.";
MyVector sam(4);
cout << "\nPush 12 values into the vector.";
for (int i = 0; i < 12; i++)
sam.push_back(i);
cout << "\nHere is sam: ";
cout << sam;
cout << "\n---------------\n";
cout << "\nCreating a vector Joe of size 4.";
MyVector joe(4);
cout << "\nPush 6 values into the vector.";
for (int i = 0; i < 6; i++)
joe.push_back(i * 3);
cout << "\nHere is joe: ";
cout << joe;
cout << "\n---------------\n";
cout << "\nTest the overloaded assignment operator \"joe = sam\": ";
joe = sam;
cout << "\nHere is sam: ";
cout << sam;
cout << "\n---------------\n";
cout << "\nHere is joe: ";
cout << joe;
cout << "\n---------------\n";
// pass a copy of sam by value
printV(sam);
cout << endl;
system("PAUSE");
return 0;
}
void printV(MyVector v)
{
cout << "\n--------------------\n";
cout << "Printing a copy of a vector\n";
cout << v;
}
My Vector.h
#pragma once
class MyVector
{
private:
int vSize;
int vCapacity;
int* vArray;
void grow();
public:
MyVector();
MyVector(int n);
MyVector(const MyVector& b);
int size() const;
int capacity() const;
void clear();
void push_back(int n);
int& at(int n) const;
MyVector& operator=(const MyVector& rho);
~MyVector();
};
MyVector.cpp
#include "MyVector.h"
#include <iostream>
using namespace std;
MyVector::MyVector()
{
vArray = nullptr;
vSize = 0;
vCapacity = 0;
}
MyVector::MyVector(int n)
{
vArray = new int[vCapacity];
vSize = 0;
vCapacity = n;
}
MyVector::MyVector(const MyVector& b)
{
vSize = b.size();
vArray = new int[vSize];
for (int i = 0; i < b.size(); i++)
{
this->vArray[i] = b.vArray[i];
}
}
int MyVector::size() const
{
return vSize;
}
int MyVector::capacity() const
{
return vCapacity;
}
void MyVector::clear(void)
{
if (vArray != nullptr)
{
delete[] vArray;
vArray = nullptr;
vSize = 0;
vCapacity = 0;
}
}
void MyVector::push_back(int n)
{
if (vCapacity == 0)
{
vCapacity++;
int* tmp = new int[vCapacity];
delete[] vArray;
vArray = tmp;
}
if (vSize >= vCapacity)
{
grow();
}
vArray[vSize] = n;
vSize++;
}
void MyVector::grow()
{
vCapacity = vCapacity + vCapacity;
int* tmp = new int[vCapacity];
for (int i = 0; i < vSize; i++)
{
tmp[i] = vArray[i];
}
delete[] vArray;
vArray = tmp;
}
int& MyVector::at(int index) const
{
if (index >= 0 && index<vSize)
{
return vArray[index];
}
else
{
throw index;
}
}
MyVector& MyVector::operator=(const MyVector& rho)
{
// test for self assignment
if (this == &rho)
return *this;
// clean up array in left hand object (this)
delete[] this->vArray;
// create a new array big enough to hold right hand object's data
vSize = rho.size();
this->vArray = new int[vSize];
// copy the data
for (int i = 0; i < rho.size(); i++)
{
this->vArray[i] = rho.vArray[i];
}
// return this object
return *this;
}
MyVector::~MyVector()
{
if (vArray != nullptr)
{
clear();
}
}
ostream& operator<<(ostream& out, const MyVector& rho)
{
for (int i = 0; i < rho.size(); i++)
{
out << rho.at(i);
}
return out;
}
Declare std::ostream& operator<<(std::ostream& out, const MyVector& rho) in My Vector.h. That function is used in Driver.cpp, therefore Driver.cpp must know about it.
If you do this, you should also #include <ostream> in My Vector.h.
To be able to use your offending operator<<() in main(), there needs to be a declaration of it visible to the compiler when compiling Driver.cpp.
That means you need to declare your operator<<() in MyVector.h.
Having the definition of operator<<() in MyVector.cpp is fine, but that is not visible to the compiler when compiling Driver.cpp