project.exe has triggered a breakpoint after system("pause") - c++

I've created my own vector, and when I try to close the console in my driver, I hit enter and get the breakpoint.
#include "MyVector.h"
#include <vector>
// Default constructor
MyVector::MyVector()
{
theData = nullptr;
vecSize = 0;
vecCap = 0;
}
// Parameterized constructor
MyVector::MyVector(int vecCap)
{
// Set vecSize to 0 and vecCap to user input (driver) plus 1 to account
// for null terminator
vecSize = 0;
this->vecCap = vecCap;
theData = new int[vecCap];
}
// Destructor
MyVector::~MyVector()
{
// Run the clear() function
clear();
}
// Copies the vector
void MyVector::copy(const MyVector& toCopy)
{
// Set size and capacity to toCopy's
this->vecCap = toCopy.vecCap;
this->vecSize = toCopy.vecSize;
// Create a temporary pointer array of ints
int* tempArray = new int[];
// Copy data from toCopy to new array
for (int i = 0; i < toCopy.size(); i++)
{
tempArray[i] = toCopy.theData[i];
}
// Point theData to the tempArray
theData = tempArray;
}
// Clears theData and resets vecCap and vecSize to 0
void MyVector::clear()
{
// Check if theData is null
if (theData != nullptr)
{
// Delete theData from heap and set to nullptr
delete[] theData;
theData = nullptr;
// Set vecSize and vecCap to 0
vecSize = 0;
vecCap = 0;
}
}
// Returns size of the vector
int MyVector::size() const
{
return vecSize;
}
// Returns capacity of the vector
int MyVector::capacity() const
{
return vecCap;
}
// Push input values into vector
void MyVector::push_back(int n)
{
// Check if vecSize is too big for vecCap
if (vecSize >= vecCap)
{
// Double vecCap through grow() function
grow(vecCap);
}
// Set theData at element vecSize to user input n, increment vecSize
theData[vecSize] = n;
vecSize++;
}
// Returns index value of vector
int MyVector::at(int vecIdx) const
{
// Check if vecIdx is within bounds
if (vecIdx >= 0 && vecIdx <= vecSize)
{
// Return vector index
return theData[vecIdx];
}
else
{
// Display out of bounds index
throw vecIdx;
}
}
// Doubles the size of the vector capacity
void MyVector::grow(int curCap)
{
// Check if curCap is 0 ro less
if (curCap <= 0)
{
// Set vecCap to CAP_GROWTH -1
vecCap = CAP_GROWTH - 1;
}
else
{
// Increase curCap by CAP_GROWTH (doubled)
vecCap = CAP_GROWTH * curCap;
}
// Create new array
int* newArray = new int[vecCap];
// Copy data to new array
for (int idx = 0; idx < vecSize; idx++)
{
newArray[idx] = theData[idx];
}
// Delete theData
delete[] theData;
// Point theData to new array
theData = newArray;
}
//
MyVector& MyVector::operator=(const MyVector& rho)
{
// Check if the implicit object's address is the same as rho
if (this != &rho)
{
// Clear the implicit object
this->clear();
// Copy the
this->copy(rho);
}
return *this;
}
//
ostream& operator<<(ostream& out, const MyVector& rho)
{
for (int idx = 0; idx < rho.size(); idx++)
{
// Output index of rho, separated by a space
out << rho.at(idx) << " ";
}
return out;
}
I've checked for somewhere I may have tried to re-delete a pointer, but I can't find anything, any it doesn't say why the exception was thrown. Any tips?

Your class does not follow the rule of 3:
What is The Rule of Three?
You are lacking a copy constructor. Your copy function is not a copy constructor. You should implement a proper copy constructor first.
In addition, your copy function has a memory leak, since you never deleted the old data.
Here is an example of a copy constructor
#include <algorithm>
//...
MyVector::MyVector(const MyVector& toCopy) : vecCap(toCopy.vecCap),
vecSize(toCopy.vecSize),
theData(new int[toCopy.capacity()])
{
std::copy(toCopy.theData, toCopy.theData + toCopy.size(), theData);
}
Now, if you really want to keep the copy function (you really don't need it, but for argument's sake you want to keep it), you can use the above copy constructor:
// Copies the vector
void MyVector::copy(const MyVector& toCopy)
{
MyVector temp(toCopy); // calls the copy constructor
std::swap(temp.vecCap, vecCap);
std::swap(temp.vecSize, vecSize);
std::swap(temp.theData, theData);
}
Note that all we did was create a temporary copy, and swap out the temporary copy's data with the current data. The temporary dies off when the function return, taking along with the old data.
Last, your assignment operator can be written using your copy function.
MyVector& MyVector::operator=(const MyVector& rho)
{
copy(rho);
return *this;
}
So in a sense, your copy function served a purpose, if the only purpose was to move some of the code around.
Actually, this is what you should have coded for your assignment operator, even without the changes I suggested. All the assignment operator should have been doing was call copy and return the current object.

In copy function, clear old data, create new data based on capacity:
void MyVector::copy(const MyVector& x)
{
clear();
vecCap = x.vecCap;
vecSize = x.vecSize;
theData = new int[vecCap];
for (int i = 0; i < x.size(); i++)
theData[i] = x.theData[i];
}
Also you are using the same names in argument, it's not wrong the way you are doing it, but it's easier to use a different name:
MyVector::MyVector(int c)
{
vecSize = 0;
vecCap = c;
theData = new int[vecCap];
}

Related

How can I create a destructor to check if the pointer is NULL? If not, delete the memory that has been allocated for the pointer

CheckedArray::CheckedArray(int size) :mSize(size){
int *mArray = new int[size];
for(int i = 0; i < size; i++)
mArray[i] = 0;
}
CheckedArray::~CheckedArray() {
if (mArray == NULL){
return;
}
else {
delete[] mArray;
}
}
I'm using dynamic memory allocation to create a new array. I want to check if the pointer is null, then return. If not, then delete. I'm getting these error messages, but I have no idea what's wrong.
(9094,0x100094600) malloc: *** error for object 0x10001e7b3: pointer being freed was not allocated
(9094,0x100094600) malloc: *** set a breakpoint in malloc_error_break to debug
To be completely clear
CheckedArray::CheckedArray(int size) :mSize(size){
int *mArray = new int[size];
for(int i = 0; i < size; i++)
mArray[i] = 0;
}
should be
CheckedArray::CheckedArray(int size) :mSize(size), mArray(new int[size]){
for(int i = 0; i < size; i++)
mArray[i] = 0;
}
Your version creates a local variable mArray which shadows the class variable of the same name.
Here is an example of what std::unique_ptr can do for you :
#include <iostream>
#include <algorithm>
#include <memory>
// https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r11-avoid-calling-new-and-delete-explicitly
// so use https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique
// prefer range based for loops, they can't go out of bounds : https://en.cppreference.com/w/cpp/language/range-for
class dynamic_int_array_t final
{
public:
// creates an "empty array" with enough memory for 4 ints.
dynamic_int_array_t() :
m_capacity{ 4ul }, // start with a capacity for 4 ints.
m_size{ 0ul }, // but actually none are stored yet
m_values{ std::make_unique<int[]>(m_capacity) }
{
}
// allows you to construct an array from a list of integers
dynamic_int_array_t(std::initializer_list<int>&& values) :
m_capacity{ values.size() },
m_size{ values.size() },
m_values{ std::make_unique<int[]>(m_capacity) }
{
std::copy(values.begin(), values.end(), m_values.get());
}
~dynamic_int_array_t() = default; // destructor will destruct unique_ptr and free memory
// non-copyable non-movable (simplifies things for now)
dynamic_int_array_t(const dynamic_int_array_t&) = delete;
dynamic_int_array_t& operator=(const dynamic_int_array_t&) = delete;
dynamic_int_array_t(dynamic_int_array_t&&) = delete;
dynamic_int_array_t& operator=(dynamic_int_array_t&&) = delete;
// begin and end allow range based for loops to work
// range based for loops don't allow you to go out of bounds.
auto begin() const
{
return m_values.get();
}
// end should point "one past" the array (that's how end works)
auto end() const
{
int* ptr = begin();
ptr += m_size;
return ptr;
}
std::size_t size() const
{
return m_size;
}
void add(const int value)
{
// if not enough memory then allocate more
if (m_size == m_capacity) grow_capacity();
// add new value at the end
m_values[m_size] = value;
m_size++;
}
// add another array to this one
void append(const dynamic_int_array_t& rhs)
{
for (int value : rhs)
{
add(value);
}
}
private:
void grow_capacity()
{
m_capacity *= 2;
// allocate new memory
auto tmp = std::make_unique<int[]>(m_capacity);
// copy content to new memory
std::copy(begin(), end(), tmp.get());
// swap new memory with tmp so m_values will now be the newly allocated memory and tmp will hold the previously allocated memory
std::swap(tmp, m_values);
// tmp will go out of scope and delete old buffer
}
std::size_t m_capacity;
std::size_t m_size;
std::unique_ptr<int[]> m_values;
};
int main()
{
dynamic_int_array_t array{ 4,5 };
for (int n = 10; n < 20; ++n)
{
array.add(n);
}
for (const int value : array)
{
std::cout << value << " ";
}
return 0;
}

Trying to Overload the << Operator, getting errors

I am working on overloading the << operator for my MyVector class. It all looks correct to me but I am getting errors when I try to run it. What am I doing wrong?
The first error is (I think) "unexpected token(s) preceding ';' " for line 84 in my .h file. (I say "I think" because I accidentally sorted the errors by description and don't know how to get it back to the default sort. If you can also advise me on how to do that, I would appreciate it.)
Thank you for your time!
MyVector.h
#pragma once
#include <iostream>
class MyVector
{
private:
//declaring variables
int *myPointer;
int vectorSize;
int vectorCapacity;
const int BASE_CAPACITY = 2;
public:
//Default Constructor
//Purpose: Create vector with default capacity of 2
//Parameter: void
//Return: None
MyVector();
//Parameterized Constructor
//Purpose: Creates a vector of capacity "n"
//Parameter: int
//Return: None
MyVector(const int);
//Default Deconstructor
//Purpose: Deletes any dynamically allocated storage
//Parameter: void
//Return: None
~MyVector();
//Copy Constructor
//Purpose: Copy the data of the vector
//Parameter: a MyVector object
//Return: None
MyVector(const MyVector&);
//Overloaded Assignment Operator
//Purpose: Copy one vector to the other when = is used
//Parameter: a MyVector object
//Return: a MyVector object
MyVector& operator=(const MyVector&);
//The size Function
//Purpose: returns the size of the vector
//Parameter: void
//Return: int
int size() const;
//The capacity Function
//Purpose: returns the capacity of the vector
//Parameter: void
//Return: int
int capacity() const;
//The clear Function
//Purpose: Deletes all elements from the vector and resets the size and capacity
//Parameter: void
//Return: None
void clear();
//The push_back Function
//Purpose: adds an integer to the vector
//Parameter: int
//Return: None
void push_back(const int);
//The at Function
//Purpose: returns the value of the element at position n
//Parameter: int
//Return: int
int at(const int) const;
// Overloaded << operation
// Purpose: Output a Vector
// Parameter: an ostream and a vector
// Return: ostream
friend ostream& operator<<(ostream& out, const MyVector& rho);
};
MyVector.cpp
#include "MyVector.h"
#include <iostream>
using namespace std;
MyVector::MyVector()
{
//create a vector with size 0 and capacity 2
vectorSize = 0;
vectorCapacity = BASE_CAPACITY;
myPointer = new int[vectorSize];
}
MyVector::MyVector(int n)
{
//create a vector of capacity n with the size 0
vectorSize = 0;
vectorCapacity = n;
myPointer = new int[vectorSize];
}
MyVector::~MyVector()
{
//check to see if 'myPointer' has a value and delete it
if (myPointer != NULL)
{
delete[] myPointer;
myPointer = NULL;
}
}
MyVector::MyVector(const MyVector& b)
{
if (b.myPointer != NULL)
{
vectorCapacity = b.vectorCapacity;
vectorSize = b.vectorSize;
myPointer = new int[vectorCapacity];
for (int i = 0; i < vectorSize; i++)
{
myPointer[i] = b.at(i);
}
}
else
{
delete[] myPointer;
}
}
MyVector& MyVector::operator=(const MyVector& rho)
{
//test for self assignment
if (this == &rho)
return *this;
// clean up the vector on the left side
delete[] this->myPointer;
// create a new vector of the correct size and capacity
vectorSize = rho.vectorSize;
vectorCapacity = rho.vectorCapacity;
this->myPointer = new int[vectorSize];
// copy the data over
for (int i = 0; i < vectorSize; i++)
{
this->myPointer[i] = rho.myPointer[i];
}
//return this object
return *this;
}
int MyVector::size() const
{
//return the size of the vector
return vectorSize;
}
int MyVector::capacity() const
{
//return the capacity of the vector
return vectorCapacity;
}
void MyVector::clear()
{
//clear the vector and reset it to a size of 0 and capacity of 2
vectorSize = 0;
vectorCapacity = BASE_CAPACITY;
delete[] myPointer;
myPointer = new int[vectorSize];
}
void MyVector::push_back(int addToVector)
{
//this variable will be used to double the capacity
const int DOUBLE_CAPACITY = 2;
//check to see if the size of the vector has reached the capacity
if (!(vectorSize < vectorCapacity))
{
//make sure the capacity of the vector is greater than 0
if (vectorCapacity > 0)
{
vectorCapacity *= DOUBLE_CAPACITY;
}
else
{
//if vector capacity is 0 or less then the capacity equals 2
vectorCapacity = BASE_CAPACITY;
}
//create a tempVector that will have double the capacity of the last vector.
int *tempVector = new int[vectorCapacity];
//copy the contents of the old vector to the tempVector
if (myPointer != NULL)
{
for (int i = 0; i < vectorCapacity; i++)
{
tempVector[i] = myPointer[i];
}
}
// delete the old array using the destructor
MyVector::~MyVector();
//set the pointer to the new tempVector
myPointer = tempVector;
}
//add the passed in value to the vector
myPointer[vectorSize] = addToVector;
//increment the size of the vector
vectorSize++;
}
int MyVector::at(int x) const
{
//throw exception if index outside the range of the vector
if (x > (vectorSize - 1))
{
throw x;
}
//return the value of the integer stored at index x
return myPointer[x];
}
ostream& operator<<(ostream& out, const MyVector& rho)
{
// output each value in the vector
for (int i = 0; i < rho.size; i++)
{
out << rho.at(i) << " ";
}
// return the ostream
return out;
}
friend ostream& operator<<(ostream& out, const MyVector& rho);
I'm assuming this is the line in question. You need to put std:: in front of ostream so it knows where to look for it. Although you put using namespace std; in the implementation file, that doesn't affect the header.
friend std::ostream& operator<<(std::ostream& out, const MyVector& rho);
On another note, don't use using namespace std;.

Invalid Allocation Size - Object Variables

I am in my first C++ this semester and am having some issues with a MyVector class I created earlier on in the class. I made variables global for the object which is a "NO NO" as my teacher said for object oriented programming. I believed I have declared the variables correctly now, but ever since I am receiving an
"Invalid allocation size: 4294967295 bytes." When calling my push_back
function.
Below is my code (MyVector.h, and MyVector.cpp), I understand that using using namespace std; is not best practice but this is how my teacher wants it.... I don't know why.
I have stepped through my code and can't identify what I need to do next. I have a feeling it is how I had the variable declared before. They were previously in the MyVector.cpp declared globally as follows before the change.
//Declarations
int vSize;
int* myArray;
int startCap = 2;
const int TWO = 2;
const int ZERO = 0;
Any help or a point in the right direction would be appreciated.
Thanks in advance!
The Call from the driver.cpp
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);
MyVector.h
class MyVector
{
public:
int vSize;
int* myArray;
int startCap;
//Constructor
MyVector ();
MyVector (int n);
//Deconstructor
~MyVector ();
//Copy Constructor
MyVector(const MyVector&);
//Overloaded Assignment Operator
MyVector& operator=(const MyVector&);
//Getter Function: size
//Purpose: Return the size of the vector
//Return Type: int
//Parameters: NONE
int size () const;
//Getter Funcation: capacity
//Purpose: Return the capacity of the vector
//Return Type: int
//Parameters: NONE
int capacity () const;
//Setter Funcation: clear
//Purpose: Clears the contents of the vector and sets the siz to zero and the capacity to two
//Return Type: void
//Parameters: NONE
void clear ();
//Setter Funcation: push_back
//Purpose: Adds integer to vector. If vector is not big enough double the vectors current capacity
//Return Type: void
//Parameters: int n
void push_back (int n);
//Getter Function: at
//Purpose: Return value of emement at position n
//Return Type: Int
//Parameters: int n
int at (int n) const;
// overloaded << operator - a nonmember
// make it a friend so it can see the array
friend ostream& operator<<(ostream& out, const MyVector& s);
};
MyVector.cpp
//default constructors
MyVector::MyVector()
{
int startCap = 2;
int vSize = 0;
myArray = new int[startCap];
}
MyVector::MyVector(int n)
{
int startCap = n;
int vSize = 0;
myArray = new int[startCap];
}
//Deconstructor
MyVector::~MyVector()
{
//deleting myArray and clearing it
if (myArray != NULL)
{
delete [] myArray;
myArray = NULL;
}
}
// Copy constructor
// Purpose: Copy the data into this Array
// Parameters: a MyVector object
// Returns: none
MyVector::MyVector( const MyVector& v)
{
// Be sure that the string is not null
if ( v.myArray != NULL )
{
// allocate storage and copy char array
startCap = v.startCap;
//theStr = new char[strlen(b.theStr) + 1];
myArray = new int[startCap];
//strncpy(theStr, b.theStr, theStrLen );
for (int i = 0; i < startCap; i++)
myArray[i] = v.myArray[i];
}
else // nothing to copy
{
myArray = NULL;
startCap = 0;
}
}
// The overloaded assignment operator
MyVector& MyVector::operator= (const MyVector& v)
{
// test for self-copy
if (this == &v)
return *this;
// Consider two cases.
if (startCap >= v.startCap) // there is room
{
if (v.myArray != NULL)
{
for (int i = 0; i < startCap; i++)
{
this->myArray[i] = v.myArray[i];
}
}
else // copying a null string
myArray = NULL;
startCap = v.startCap;
return *this;
}
else // not enough room
{
// delete the original array
delete [] myArray;
startCap = v.startCap;
if (startCap > 0) // okay, something to copy
{
// allocate the storage and copy
myArray = new int[startCap + 1];
for (int i = 0; i < vSize; i++)
{
this->myArray[i] = v.myArray[i];
}
}
else // nothing to copy
myArray = NULL;
return *this;
}
}
//Getter Function: size
//Purpose: Return the size of the vector
//Return Type: int
//Parameters: NONE
int MyVector::size() const
{
return vSize;
}
//Getter Funcation: capacity
//Purpose: Return the capacity of the vector
//Return Type: int
//Parameters: NONE
int MyVector::capacity() const
{
return startCap;
}
//Setter Funcation: clear
//Purpose: Clears the contents of the vector and sets the siz to zero and the capacity to two
//Return Type: void
//Parameters: NONE
void MyVector::clear()
{
//clearing the array and setting the array to the default cap of 2 and size of 0
if (myArray != NULL)
{
delete [] myArray;
myArray = NULL;
}
vSize = 0;
startCap = 2;
int* myArray = new int[startCap];
}
//Setter Funcation: push_back
//Purpose: Adds integer to vector. If vector is not big enough double the vectors current capacity
//Return Type: void
//Parameters: int n
void MyVector::push_back(int n)
{
//verifying the we are not writting the value
//past the capacity of the array
if(vSize + 1 > startCap)
{
//Doubling the array size
startCap = vSize * 2;
//creating a temp array
int* temp = new int[startCap];
//for loop copying the contents of myArray to temp
for (int i = 0; i < vSize; i++)
{
temp[i] = myArray [i];
}
//deleting the myArray
delete[] myArray;
//copying myArray from temp
myArray = temp;
}
//finding the end of the array and incrementing and adding one to the array
myArray[vSize] = n;
vSize++;
}
//Getter Function: at
//Purpose: Return value of emement at position n
//Return Type: Int
//Parameters: int n
int MyVector::at(int n) const
{
//If statment that returns value of the point in the array
//or throws an error telling the user the index at which it failed
if(n < vSize)
return myArray[n];
throw n;
}
ostream& operator<<(ostream& out, const MyVector& s)
{
for (int i = 0; i < s.vSize; i++)
out << s.myArray[i] << ' ';
return out;
}
you are creating a same variable within the constructor and clear, which has the same name is the one in the class, initialize it.
and by the time you leave the constructor or clear, the main variables, don't get any changes.
its an initializing issue, especially the ones in the constructor
in clear function
int* myArray = new int[startCap];
should be
myArray = new int[startCap];
also inside the constructor
int startCap = n;
int vSize = 0;
should be
startCap = n;
vSize = 0;
When you want to assign to an instance variable, don't put the type on the name. That'll create a local variable with the same name as the instance variable instead of assigning to the actual instance variable, causing your instance variables to have incorrect, possibly even uninitialized values. This problem shows up in your first two constructors and your clear method.

Heap error during cout C++

I'm getting an error when trying to cout the return value of Data[index]. If anyone could help me that would be awesome. I know usually these errors are caused by allocated conflicting memory or having a pointer reference a deleted index, etc. Although I don't delete anything so I don't know where this error is coming from.
Header file:
#pragma once
#define INITIAL_CAPACITY 100
#define CAPACITY_BOOST 40
//Encapsulates the C-array
template <typename DATA_TYPE>
class Vector
{
public:
//Default / init-constructor hybrid
Vector(int initialCapacity = INITIAL_CAPACITY)
{
Size=0;
Capacity = initialCapacity;
//Allocate the encapsulated C-array
Data= new DATA_TYPE[Size];
}
//MUST HAVE A COPY-CONSTRUCTOR THAT PERFORMS deep-copy
Vector(const Vector& copyFrom)
{
//Necessary to prevent assignment operator from crashing
//because it will attempt to Delete[] Data whe the Data pointer is garbage.
Data=NULL;
//Use assignment operator to perform the deep copy
*this = copyFrom;
}
//The class MUST have a destructor
~Vector()
{
//Deallocate memory that our class has allocated
delete[] Data;
}
//MUST have an assignment operator that performs deep copy
Vector& operator =(const Vector& copyFrom)
{
//0. Delete the old memory
delete[] Data;
//1. Copy size and Capacity
Size = copyFrom.Size;
Capacity = copyFrom.Capacity;
//2. Allocate Memory
Data = new DATA_TYPE[Capacity];
//3. Copy elemenets
for(int i=0; i < Size; i++)
Data[i]= copyFrom.Data[i];
//All assignment operators should return *this
return *this;
}
//Get accessors to return the values of Size and Capacity
int GetSize() const
{
return this->Size;
}
int GetCapacity() const
{
return Capacity;
}
void Insert(int insertAt, const DATA_TYPE& newElement)
{
//**ASSIGNMENT**
//1. Determine if we have enough capacity for extra element(reallocate)
Size=GetSize();
if(Size>=Capacity)
{
Capacity += CAPACITY_BOOST;
}
//Use a function to check bounds.
if((insertAt > Capacity)||(insertAt < 0))
{
throw "Index is out of bounds";
}
//2.Move the tail
for (int i=Size+1; i > insertAt; i--)
Data[i]=Data[i-1];
//3.Insert element
Data[insertAt]= newElement;
}
//Inserts a new element at the end fo the Vector and increments the size
void Add(const DATA_TYPE& newElement)
{
Insert(Size, newElement);
Size++;
}
void Remove(int index)
{
delete Data[index];
for(i=index; i < Size-1; i++)
Data[i]=Data[i+1];
Size--;
Capacity=Size;
//**ASSIGNMENT**
//Resize. Shrink vector when you have too much capacity
//TEST EVERYTHING
}
// Index operator
DATA_TYPE operator[] (int index) const
{
// Check the bounds and throw an exception
if ( (index < 0) || (index >= Size) )
throw "Error";
return Data[index];
}
private:
//The count of actually used C-array elements
int Size;
//The count of the allocated C-array elements
int Capacity;
//The encapsulated C-array (pointer)
DATA_TYPE* Data;
};
Main:
#include <iostream>
#include "vector.h"
using namespace std;
#define TEST_CAPACITY 100
#define TEST_SIZE 10
template<typename DATA_TYPE>
void PassByValueTest(Vector<DATA_TYPE>passedByValue)
{
}
void main()
{
//myVector is initialized using the default constructor
Vector<int> myVector;
//Populate myVector with some test values
for (int i=0; i< TEST_SIZE; i++)
myVector.Add(i);
//myOtherVector initialized using the init-constructor, initial capacity is 10
//Vector<int> myOtherVector(TEST_CAPACITY);
//Test by passing vector by value
/*
PassByValueTest(myVector);
myVector = myOtherVector;
*/
for(int i = 0; i < TEST_SIZE; i++)
{
cout << myVector[i];
}
system("pause");
}
I guess you should switch:
Data= new DATA_TYPE[Size];
to
Data= new DATA_TYPE[Capacity];
you are doing Data = new DATA_TYPE[0];
Vector(int initialCapacity = INITIAL_CAPACITY)
{
Size=0; // <<<---
Capacity = initialCapacity;
//Allocate the encapsulated C-array
Data= new DATA_TYPE[Size]; // note Size is 0
}
Then access to Data[i] is undefined behavior:
for(int i = 0; i < TEST_SIZE; i++)
{
cout << myVector[i];
}
Side note, you should return int from main, there is no void main in standard:
int main()
{
}

How do you copy an object of a class to another object of the same class by using '='

How do you copy an object of a class to another object of the same class just by using '='. I know that we have to overload the operator. here's what I have so far
#include<iostream>
#include<conio.h>
#include<iomanip>
using namespace std;
class arr
{
public:
int *arr1;
int len;
arr& operator = (const arr& eq) //for copying two arrays. <--- my overloader
{
arr temp1(eq.len);
arr *pttemp;
int i=0;
//temp.arr1=new int[eq.len];
//temp.len = eq.len;
for(i = 0 ; i < eq.len ; i++)
{
temp1.arr1[i] = eq.arr1[i];
}
pttemp = &temp1;
return temp1;
};
friend istream& operator >> (istream& ist, arr & r)
{
static int i = 0;
int *arrNew;
if (i == r.len)
{
r.len *=2;
arrNew = new int[r.len]; // allocate the new array
for(int j = 0; j < r.len/2; j++)// copy the old array to the first half of the new array
arrNew[j] = r.arr1[j];// delete the old array
delete [] r.arr1;// let arr point to the new array and continue use arr
r.arr1 = arrNew;
delete arrNew;
}
ist>>r.arr1[i];
i++;
return ist;
}
arr() //initializing constructor
{
len = 5;
arr1 = new int[len];
};
arr(int size) //initializing constructor with args
{
len = size;
arr1 = new int[len];
};
arr(arr& a) : arr1(a.arr1) //copy constructor
{
arr1 = new int[len];
};
~arr() //delete constructor
{
delete arr1;
};
};
void main()
{
int size = 5,i,temp,trig = 0;
arr orig(size), asc(size), desc(size);
//generate random numbers for orig
for (i = 0 ; i < size ; i++)
{
orig.arr1[i] = rand();
}
//copy original set to asc and desc
asc = orig;
desc = orig;
//sorting ascending
for (i = 0 ; i < size-1 ; i++)
{
trig = 1;
if (asc.arr1[i] < asc.arr1[i+1])
{
temp = asc.arr1[i];
asc.arr1[i] = asc.arr1[i+1];
asc.arr1[i+1] = temp;
trig = 0;
}
if (trig = 1)
break;
if (i == size - 1)
{
i = 0;
}
}
//sorting descending
for (i = 0 ; i < size-1 ; i++)
{
trig = 1;
if (desc.arr1[i] > desc.arr1[i+1])
{
temp = desc.arr1[i];
desc.arr1[i] = desc.arr1[i+1];
desc.arr1[i+1] = temp;
trig = 0;
}
if (trig = 1)
break;
if (i == size - 1)
{
i = 0;
}
}
//printing
cout<<"Original Array: ";
for (i = 0 ; i < size ; i++)
{
cout<<orig.arr1[i]<<" ";
}
cout<<endl;
cout<<"Ascending Array: ";
for (i = 0 ; i < size ; i++)
{
cout<<asc.arr1[i]<<" ";
}
cout<<endl;
cout<<"Descending Array: ";
for (i = 0 ; i < size ; i++)
{
cout<<desc.arr1[i]<<" ";
}
cout<<endl;
getch();
}
It compiles properly but it ('asc' and 'desc') displays numbers that are different from the 'orig' object.
The proper solution is something like this:
struct Foo
{
std::vector<int> arr;
friend std::ifstream & operator>>(/*...*/);
};
The implicitly defined assignment operator already does exactly what you need, and clever code reuse is the heart of C++ programming ("a language for library design").
If you want to write it by hand, you have to make the copy yourself:
struct Bar
{
unsigned int len;
int * arr;
Bar & operator=(Bar const & rhs)
{
len = rhs.len;
delete[] arr;
arr = new int[len];
for (unsigned int i = 0; i != len; ++i) { arr[i] = rhs.arr[i]; }
return *this;
}
Bar() : len(), arr() { }
// more constructors
Bar(Bar const &); // exercise: write this!
~Bar() { delete[] arr; }
};
This is a terrible, terrible idea, though, since this pattern doesn't generalize at all: it isn't exception safe -- imagine one of the copies in the for-loop threw an exception. Now you've lost your original data and leaked memory.
A better solution would be to allocate a temporary buffer first:
int * temp = new int[len];
for (...) temp[i] = rhs.arr[i];
delete[] arr;
arr = temp;
Now this code is quickly getting very ugly, and imagine you had more than one of those!
In a nutshell: use std::vector.
You don't need a temporary array object in the assignment operator, and you should copy to the array in this, and then return *this:
arr &operator=(const arr &eq)
{
// If "this" already has an array, then delete it
if (arr1)
delete [] arr1;
// Create a new array of the same length as the one we're assigning from
len = eq.len;
arr1 = new int [len];
// And copy the array
memcpy(arr1, eq.arr1, len * sizeof(int));
// Returning "*this" allows the assignment operator to be chained
return *this;
}
what you have implemented in operator overloading is quite confusing and seems wrong to me
arr& operator = (const arr& eq) //for copying two arrays. <--- my overloader
{
arr temp1(eq.len);
arr *pttemp;
int i=0;
//temp.arr1=new int[eq.len];
//temp.len = eq.len;
for(i = 0 ; i < eq.len ; i++)
{
temp1.arr1[i] = eq.arr1[i];
}
pttemp = &temp1;
return temp1;
};
1.why are you creating a new object temp?
2.why create a pointer of type arr. and assigning pttemp to point to temp whose scope is with in the function and then you are not using
it anywhere!!
you need not create a new object inside the function as "this" pointer is implicitly passed to the function.
you should overload it this way
arr& operator = (const arr& source)
{
//this->len = source.len;
len = source.len;
for(int i=0;i < source.len ; i++)
{
//this->arr1[i] = source.arr1[i];
arr1[i] = source.arr1[i];
}
return *this;
}
Your copy constructor also looks wrong, it doesn't copy the contents of the array.
I agree with Kerrek that you should use vector. But since you appear to be trying to re-implement vector for yourself, here's a simple "correct" way to manage the resources in your class, for illustration:
class arr
{
public:
// switch order of data members, we want to initialize "len" first
int len;
int *arr1;
// default constructor
// you could use "new int[len]()" instead, to zero-initialize the array
arr() : len(5), arr1(new int[len]) {}
// constructor with size
arr(int size) : len(size), arr1(new int[len]) {}
// copy constructor
arr(const arr &rhs) : len(rhs.len), arr1(new int[len]) {
std::copy(rhs.arr1, rhs.arr1 + len, arr1);
}
// destructor
~arr() {
delete[] arr1; // *not* "delete", you *must* use "delete[]"
}
// swap function (this is useful, observe that it cannot throw)
void swap(arr &rhs) {
std::swap(len, rhs.len);
std::swap(arr1, rhs.arr1);
}
// assignment operator
arr &operator=(arr temp) { // parameter by value uses the copy ctor
// so, anything that could throw (the allocation) is complete,
// before we make any modifications to this object.
// see how useful "swap" is, and the fact it cannot throw?
swap(temp);
return *this;
}
// for C++11
// move constructor
arr(arr &&rhs) : len(rhs.len), arr1(rhs.arr1) {
rhs.arr1 = 0;
}
};
Btw, the name of the data member arr1 makes me fear that you're going to add a second array later. Do not do this, it's far more trouble to write a class that correctly manages two resources, than it is to write a class that correctly manages one resource and another class that has two of those as data members.