Dynamic array implementaion c++ , Overloading assignment operator - c++

vector<int> a = {1,2,3};
a[1] = 54; // I want to achieve this in my Darray implementation
int i = 0;
a[i] = 10 // This also
I am trying to implement dynamic arrays in c++. Below is my code :
//-------- means it has not been defined yet
// custom Exception class for handling bizzare situations
#include <iostream>
using namespace std;
class MyException {
public:
MyException() {
cout << "\nException occured !! Program will terminate...\n";
exit(0);
}
MyException(string message) {
cout << "\nException occured : " << message
<< ".\nProgram will terminate...\n";
exit(0);
}
};
//================================================================================
// class for Dyanamic array
template <typename T> //
class Darray {
T *arr; // Dyanamic array
size_t len, cap; // length and capacity
/*
len : number of elements currently Darray contains
cap : number of elements Darray can hold without resizing
*/
public:
Darray();
Darray(size_t);
Darray(Darray<T> &);
// Darray(T *); //---------------
size_t capacity();
size_t length();
void resize(size_t);
bool empty();
T operator[](int);
T operator[](T);
void operator=(T); //-------------
void operator=(Darray);
void push(T);
T pop();
T back();
T elemAt(int);
T front();
T *data();
void assign(Darray); //---------------
void assign(T *); //--------------
void insertAt(T, int); //--------------
void erase(); //-------------
void clear(); //---------------
void swap(Darray, Darray); //---------
};
//================================================================================
// default constructor for 0 capacity
template <typename T> //
Darray<T>::Darray() {
arr = new T[0];
len = 0;
cap = 0;
}
//================================================================================
// parameterized constructor with given cap
template <typename T> //
Darray<T>::Darray(size_t cap) {
arr = new T[cap];
this->cap = cap;
len = 0; // no elements initially
}
//================================================================================
// copy constructor with given Darray
template <typename T> //
Darray<T>::Darray(Darray<T> &temp) {
cap = temp.capacity();
len = 0;
arr = new T[cap];
while (len < temp.length()) {
arr[len] = temp[len];
len++;
}
}
//================================================================================
// operator[] for getting elements
template <typename T> //
T Darray<T>::operator[](int index) {
if (empty())
throw MyException("Darray is empty");
if (index < 0 || index > len - 1)
throw MyException("Invalid index. Index should be in range 0 to length-1");
return arr[index];
}
//================================================================================
// to check if Darray is empty
template <typename T> //
bool Darray<T>::empty() {
return len < 1;
}
//================================================================================
// push elements at the end
template <typename T> //
void Darray<T>::push(T element) {
if (len == cap)
resize(cap + (cap / 2) + 1); // resizing the array
// +1 to ensure arrays of size 0 or 1 are also resized ;-)
arr[len] = element;
len++;
}
//================================================================================
// remove and gives the last element of Darray
template <typename T> //
T Darray<T>::pop() {
if (empty())
throw MyException("Darray is empty");
return arr[--len];
}
//================================================================================
// gives the last element of Darray
template <typename T> //
T Darray<T>::back() {
if (empty())
throw MyException("Darray is empty");
return arr[len - 1];
}
//================================================================================
// gives the first element of Darray
template <typename T> //
T Darray<T>::front() {
if (empty())
throw MyException("Darray is empty");
return arr[0];
}
//================================================================================
// gives element at pos
template <typename T> //
T Darray<T>::elemAt(int index) {
if (empty())
throw MyException("Darray is empty");
if (index < 0 || index > len - 1)
throw MyException("Invalid index. Index should be in range 0 to length-1");
return arr[index];
}
//================================================================================
// length gives number of elements currently present in the array
template <typename T> //
size_t Darray<T>::length() {
return len;
}
//================================================================================
// capacity gives total capacity of the array
template <typename T> //
size_t Darray<T>::capacity() {
return cap;
}
//================================================================================
// returns a pointer to first element of Darray
template <typename T> //
T *Darray<T>::data() {
if (empty())
return NULL;
return arr;
}
//================================================================================
// resize the array to given size
template <typename T> //
void Darray<T>::resize(size_t newSize) {
if (newSize < 0)
throw MyException("Size cannot be negative");
if (newSize == cap) // no need to resize
return;
T *temp; // temp array to hold the elements temporarily
size_t t; // t holds the number of elements to be copied in the resized Darray
if (newSize < len) {
t = newSize;
temp = new T[newSize];
// copying to temp,new size is less, some elements will be lost
for (int i = 0; i < t; i++) {
temp[i] = arr[i];
}
} else {
t = len;
temp = new T[len];
// copying all the elements from original array to temp
for (int i = 0; i < t; i++) {
temp[i] = arr[i];
}
}
arr = new T[newSize]; // resizing the Darray
// copying elements from temp to original Darray
for (int i = 0; i < t; i++) {
arr[i] = temp[i];
}
cap = newSize;
len = t;
}
int main()
{
Darray<char> a(0);
a.push('A');
a.push('B');
a.push('C');
a.push('D');
a.push('E');
// a.push('F');
// a.push('G');
// a.push('H');
for (int i = 0; i < a.length(); i++) {
cout << a[i] << " ";
}
cout << a.length() << " " << a.capacity() << endl;
return 0;
}
Is overloading the assignment operator to assign elements at given index of my dynamic array possible?
Something like:
Darray<int> a(5);
a[1] = 26;
Also if I overload the constructor to take array as T* and create a Darray(0) it becomes ambiguous (null pointer and Darray of size 0).
How to overcome this?

Your subscript operator returns by value. That means it returns a brand new copy.
Assigning to this copy will not change the original inside your "array".
You should return by reference instead:
T& operator[](int);
And you should probably add a "constant" overload as well:
T const& operator[](int) const;

Related

How to insert element using template

I have some doubts about my insert method. it is compiling, but with no result. I presume that it is containing some coding errors. Can you help me resolving this? Thanks in advance.
private:
T* elements;
int capacity;
int nbElements;
template <class T>
void TableDynamic<T>::insert(const T& element, int index)
{
int *temp = new int[capacity] ;
for(int i =0; i<nbElements; i++)
{
temp[i] = element;
}
delete[] elements;
int *elem = new int[capacite];
}
I have written some code for you. see if its works for you.
#include <iostream>
using namespace std;
// insert element using template
template <class T>
class TableDynamic
{
private:
T *elements;
int capacity;
int nbElements;
public:
TableDynamic(int capacity)
{
this->capacity = capacity;
this->nbElements = 0;
this->elements = new T[capacity];
}
void insert(const T &element, int index)
{
if (index < 0 || index > nbElements)
{
cout << "Index out of range" << endl;
return;
}
if (nbElements == capacity)
{
cout << "Table is full" << endl;
return;
}
for (int i = nbElements; i > index; i--)
{
elements[i] = elements[i - 1];
}
elements[index] = element;
nbElements++;
}
void print()
{
for (int i = 0; i < nbElements; i++)
{
cout << elements[i] << " ";
}
cout << endl;
}
};
int main()
{
TableDynamic<int> table(10);
table.insert(10, 0);
table.insert(20, 1);
table.insert(30, 2);
// print the table
table.print();
return 0;
}
temp and elem variables types should be T* , and in the last line you have wrote capacite, should be capacity
Resizing should only be done, if the capacity is insufficient.
Furthermore you didn't copy any of the old elements over; you simply fill every element with the new element.
Also you're generating an array of ints regardless of element type which will only allow for element types int or const int.
The code should look something like this:
template <class T>
void TableDynamic<T>::insert(const T& element, int index)
{
if ((index > nbElements) || (index < 0))
{
throw std::runtime_error("invalid index");
}
if ((nbElements + 1) > capacity)
{
// reallocate array
auto newCapacity = CalculateNewCapacity(capacity, nbElements + 1); // todo: implement capacity calulation function
auto temp = std::make_unique<T[]>(newCapacity);
temp[index] = element; // note copying may result in an error, moving shouldn't, so copy first
// move first half
std::move(elements, elements + index, temp.get());
// move second half
std::move(elements + index, elements + nbElements, temp.get() + (index + 1));
// replace array
delete[] elements;
elements = temp.release();
capacity = newCapacity;
}
else
{
// make room for new element
std::move_backward(elements + index, elements + nbElements, elements + (nbElements + 1));
// insert new element
elements[index] = element;
}
++nbElements;
}

How do I implement vector reallocation?

I am attempting to implement my own version of a C++ vector, but I'm having issues with my reallocation function when the size becomes equal to the capacity. Specifically, when the debugger reaches the delete line, I am given a heap corruption error stating that the application wrote to memory after the end of the heap buffer. Could someone give advice on why my approach is wrong? Please let me know if there is any other information needed that would be helpful in solving this issue.
EDIT: I have added all of my current code so that others can test the program and reproduce the issue.
Header file:
#ifndef VECTOR_H
#define VECTOR_H
template <class ItemType> class Vector{
public:
Vector();
Vector(int capacity);
int size();
int capacity();
bool is_empty();
ItemType at(int index);
void push(ItemType newItem);
void printItems();
~Vector();
private:
int m_capacity; // number of items we can hold
int m_size; // current number of items
int m_unitSize; // size of one unit (used for arithmetic in indexing)
ItemType* m_vectorPtr; // pointer to actual vector
void reallocate(); // reallocates memory if array is filled
};
#endif
Implementations and testing:
#include <iostream>
#include "Vector.h"
#include <assert.h>
// default constructor
template <class ItemType>
Vector<ItemType>::Vector()
:m_capacity(0), m_size(0) {
m_unitSize = sizeof(ItemType);
m_vectorPtr = nullptr;
}
// constructor with given number of items
template <class ItemType>
Vector<ItemType>::Vector(int capacity)
:m_size(0){
int x = 1;
while (x <= capacity) {
x *= 2;
}
m_unitSize = sizeof(ItemType);
m_capacity = x;
m_vectorPtr = new ItemType[capacity];
}
// return total possible items
template <class ItemType>
int Vector<ItemType>::capacity() {
return m_capacity;
}
// return current number of elements
template <class ItemType>
int Vector<ItemType>::size() {
return m_size;
}
// return whether the vector is currently empty
template <class ItemType>
bool Vector<ItemType>::is_empty() {
return m_size == 0;
}
// return the item at a given index
template<class ItemType>
ItemType Vector<ItemType>::at(int index) {
return m_vectorPtr[index];
}
// reallocate the array if it becomes full
template <class ItemType>
void Vector<ItemType>::reallocate() {
if (m_size >= m_capacity) {
// allocate a new array twice the capacity
m_capacity *= 2;
ItemType* newVector = new ItemType[m_capacity];
for (int i = 0; i < m_size; i++) {
newVector[i] = m_vectorPtr[i];
}
delete[] m_vectorPtr;
m_vectorPtr = newVector;
}
}
// push an item onto the vector at the end
template<class ItemType>
void Vector<ItemType>::push(ItemType newItem) {
if (m_size >= m_capacity) {
// reallocate memory for the vector
reallocate();
}
// push new item onto vector
m_vectorPtr[m_size] = newItem;
m_size++;
}
template <class ItemType>
void Vector<ItemType>::printItems() {
for (int i = 0; i < m_size; i++) {
std::cout << m_vectorPtr[i] << " ";
}
std::cout << std::endl;
}
template <class ItemType>
Vector<ItemType>::~Vector() {
delete[] m_vectorPtr;
}
// test here
int main() {
// initialize a vector
int startingCapacity = 3;
Vector<int> testVector(startingCapacity);
assert(testVector.capacity() == 4 &&
testVector.size() == 0 &&
testVector.is_empty() == true);
// add two items to the vector
testVector.push(3);
testVector.push(7);
assert(testVector.capacity() == 4 &&
testVector.size() == 2 &&
testVector.is_empty() == false);
// print the two items
testVector.printItems();
// add past capacity to test reallocate
testVector.push(5);
testVector.push(8);
testVector.push(6);
assert(testVector.capacity() == 8 &&
testVector.size() == 5 &&
testVector.is_empty() == false);
testVector.printItems();
std::cout << "All test cases passed." << std::endl;
return 0;
}
You have to reallocate before you change m_size because the for loop will be incorrect if m_size > m_capacity and you'll access m_vectorPtr past its size. And make sure the new capacity is big enough (m_capacity *= 2) > new_size
template <class ItemType>
void Vector<ItemType>::reallocate(size_t new_size) {
if (new_size > m_capacity) {
// allocate a new array twice the capacity
if (m_capacity == 0)
m_capacity = 10;
while (m_capacity < new_size)
m_capacity *= 2;
ItemType* newVector = new ItemType[m_capacity];
for (int i = 0; i < m_size; i++) {
newVector[i] = m_vectorPtr[i];
}
delete[] m_vectorPtr;
m_vectorPtr = newVector;
}
}
And here sample push_back method reallocating before changing m_size:
void push_back(ItemType item) {
reallocate(m_size + 1);
m_vectorPtr[m_size] = item;
m_size++;
}
Demo
UPDATE
You have a small bug in the constructor NOT:
m_vectorPtr = new ItemType[capacity];
but
m_vectorPtr = new ItemType[m_capacity];
because capacity is the requested one, not the power of two you want (3, not 4 in your test).

Dynamic Array - Finding Capacity

I have been looking through the std::vectors source code and looking at how it's capacity (vector.capacity()) function works, i'm not quite understanding how i would implement it into my Dynamic array source code. I would not just be returning the current container size would i. e.g dynarray.size().
,Thanks
#include <iostream>
#include <vector>
#include <iterator>
#pragma once
template<typename T>
class DynamicArrayIter
{
public:
DynamicArrayIter(T* data) : newData(data) { }
//DynamicArrayIter(const DynamicArrayIter& o); // Copy constructor
//DynamicArrayIter& operator=(const DynamicArrayIter& o); // Assignment operator
DynamicArrayIter operator++() { DynamicArrayIter i = *this;newData++; return i;}
DynamicArrayIter operator++(int junk) {newData++;return *this; }
T& operator*() {return *newData; }
bool operator==(const DynamicArrayIter& rhs) {return newData == rhs.newData; }
bool operator!=(const DynamicArrayIter& rhs) { return newData != rhs.newData;}
DynamicArrayIter<T> operator+(int _i)
{
DynamicArrayIter<T> iter = *this;
for (int i = 0; i < _i; ++i)
{
if (iter.newData) //If there's something to move onto...
++iter;
else
break;
}
return iter; //Return regardless of whether its valid...
}
private:
T* newData;
};
template<typename T>
class DynamicArray
{
public:
DynamicArray<T> operator=(const DynamicArray<T>&);//Dynamic Array equals Dynamic Array
DynamicArray();//Constructor
~DynamicArray();//Destructor
void push_back(const T&);//Push back a new element into the DynArray
void pop_back();//Pop an element off the back of the DynArray
void print();//Prints out what is in the container
bool empty();//Empty the DynArray container
void reserve(int);//Reserver a size of which the Dynarray can reach, once it reachers the limit it will increase etc.
void resize(int);//resize the Dynrray container data will be carried into the new size either cutting off eccess data or reserving space for more.
void swap(DynamicArray<T>);//Swap the contents in the Dynarray with another Dynarray containers.
void assign(size_t,T);//Assign new content to the Dynarray, replacing the current elements and changing its size accordingly
void assign(DynamicArrayIter<T>, DynamicArrayIter<T>);//Assign new content to the Dynarray, replacing the current elements and changing its size accordingly
void insert(DynamicArrayIter<T>,T);//Insert a element at a certain positon elements will be moved and adjusted accordingly
void erase(DynamicArrayIter<T>);//Erase an element at a certain postion
void erase(DynamicArrayIter<T>,DynamicArrayIter<T>);//Erase an element at a certain postion
T& at(int );// Element postion at index
T& front();//elements t postion
T& back();//elements back position
T& operator[] (int);//subscript location access
size_t capacity();//capacity of the container
size_t max_size();//max size of the vontainer
DynamicArrayIter<T> begin();//Begin on the container/DynArray - Iterator uses this to grab the begin of the Dynarray
DynamicArrayIter<T> end();//End on the container/DynArray - Iterator uses this to grab the End of the Dynarray
void clear();//Clear the whole container
int size();//Size of the current container returns sizeofarray
private:
T* myArray;//Where data is stored
int sizeofarray = 0;//size of the current container
};
template<typename T>
inline DynamicArray<T> DynamicArray<T>::operator=(const DynamicArray<T>&newDynArray)
{
myArray = new T[newDynArray.size()];
for (size_t i = 0; i < newDynArray.size(); i++)//will make the current array the size of the new one
{
myArray[i] = newDynArray.myArray[i];//Current Dynarray = the pass in Dynarray - Steps through changign each element
}
return newDynArray;//return the passed data
}
template<typename T>
inline DynamicArray<T>::DynamicArray()
{
myArray = new T[sizeofarray];//Creating a new Dynarray of size
}
template<typename T>
inline DynamicArray<T>::~DynamicArray()
{
delete[] myArray;//deleting the Dynarray
}
template<typename T>
inline void DynamicArray<T>::push_back(const T& pusheddata)
{
T *temp = myArray;//Creating a temp array with the value of the current Dynarray
myArray = new T[++sizeofarray];//Dynarray = new Dynarray of current size + 1 // Size is being incremented from this
myArray[sizeofarray - 1] = pusheddata;//Pushing the element onto the back of the Array
for (int i = 0; i < sizeofarray - 1; ++i)//It is sizearray - 1 as we dont the temp does not have the data we just pushed onto the back
{
myArray[i] = temp[i];//going through a loop putting the data from the temp we created back into the DynArray.
}
delete[] temp;//delete the temp
}
template<typename T>
inline void DynamicArray<T>::pop_back()
{
T *temp = myArray;//Creating a temp array with the value of the current Dynarray
myArray = new T[sizeofarray--];//Dynarray = new Dynarray of current size - 1 // Size is being decreased from this
for (int i = 0; i < sizeofarray; ++i)
{
myArray[i] = temp[i];//Dynarray equals the temp values
}
delete[] temp;//Delete the temp
}
template<typename T>
inline void DynamicArray<T>::print()
{
for (size_t i = 0; i < sizeofarray; i++)
{
std::cout << myArray[i] << std::endl;//Just looping through and printing the element until it hits size.
}
}
template<typename T>
inline bool DynamicArray<T>::empty()
{
if (size() == 0)
{
return true;//return true if size is 0
}
return false;//return flase if size >=1
}
template<typename T>
inline void DynamicArray<T>::reserve(int r_size)
{
sizeofarray = r_size;//size = the reserve size
}
template<typename T>
inline void DynamicArray<T>::resize(int newsize)
{
T *temp = myArray;//Creating a temp with the current Dynarray inside of it
myArray = new T[newsize];//Dynarray = a new Dynarray of size (newsize)
for (int i = 0; i < newsize; ++i)
{
myArray[i] = temp[i];//Setting the Dynarrays elements to the temps
}
for (int i = sizeofarray; i < newsize; i++)
{
myArray[i] = NULL;//Set the elements outside the size allowed to NULL
}
sizeofarray = newsize;//Size = new size
delete[] temp;//delete the temp
}
template<typename T>
inline void DynamicArray<T>::swap(DynamicArray<T> newSwap)
{
clear();//clear the current Dynarray
for (size_t i = 0; i < newSwap.sizeofarray; i++)
{
myArray[i] = newSwap.myArray[i];//Newly cleared Dynarray elements = passed in swapped data
sizeofarray++;//increment the size
}
}
template<typename T>
inline void DynamicArray<T>::assign(size_t n, T val)
{
clear();//Clear the Dynarray
myArray = new T[n];//Dynarray = new Dynarray of size_t n
for (size_t i = 0; i < n; i++)//for i < size_t n
{
myArray[i] = val;//Dynarray = val passed through
sizeofarray++;//increment the size of the Dynarray
}
}
template<typename T>
inline void DynamicArray<T>::assign(DynamicArrayIter<T> first, DynamicArrayIter<T> last)
{
int n = 0;//temp size holder
for (DynamicArrayIter<T> iter = first; iter != last; ++iter) {
n++;//increment the temp size holder
}
clear();//clear the Dynarray
myArray = new T[n];//Make a new Dynarray and its size is the temp size holders
for (DynamicArrayIter<T> newiter = first; newiter != last; ++newiter) {
myArray[sizeofarray] = *newiter;//Iterate through and set each element to the value passed in
sizeofarray++;//incremenet the size
}
}
template<typename T>
inline void DynamicArray<T>::insert(DynamicArrayIter<T> position, T val)
{
int sizeofthis = 0;//temp size holder for iter
int j = 0;//Index position // increments when position is meet
for (DynamicArrayIter<int> iter = begin(); iter != position; ++iter){
++sizeofthis;//increase the temp size holder fo riter
}
T *temp = myArray;//Create a new temp Dynarray
sizeofarray += 1;//temp size hodler + 1
myArray = new T[sizeofarray];//Dynarray = new Dynarray of temp size holder for iter
for (size_t i = 0; i < sizeofarray; i++)
{
if (i == sizeofthis)//if the for loops i = tempsize holders
{
myArray[sizeofthis] = val;//Dynarray element = val being passed in
j++;//Index pos ++
}
myArray[i + j] = temp[i];//Dynarray = Temps values // Will change when inserted pos is reached // dynamically chagne size
}
delete[] temp;//delete temp
}
template<typename T>
inline void DynamicArray<T>::erase(DynamicArrayIter<T> position)
{
int sizeofthis = 0;//temp size holder for iter
int j = 0;//index pos//increments wehn pos is met
for (DynamicArrayIter<int> iter = begin(); iter != position; ++iter) {
++sizeofthis;//increment the temp size holder
}
T *temp = myArray;//temp = current Dynarray
sizeofarray -= 1;//size decreased by 1
myArray = new T[sizeofarray];//new Dynarray of the new size
for (size_t i = 0; i < sizeofarray; i++)
{
if (i == sizeofthis)//if the loops i reaches the temp size holders value
{
myArray[sizeofthis] = myArray[sizeofthis + 1];//Dynarray at sizeoftihs = Dynarrays next element
j++;//index pos ++
}
myArray[i] = temp[i + j];//Dynarray = the temp[idexpos will be greater > 0 if i == sizeofthis]
}
delete[] temp;//delete the temp
}
template<typename T>
inline void DynamicArray<T>::erase(DynamicArrayIter<T> first, DynamicArrayIter<T> last)
{
int sizeofthis = 0;
for (DynamicArrayIter<int> iter = first; iter != last; ++iter) {
++sizeofthis;
}
T *temp = myArray;
sizeofarray = sizeofarray - sizeofthis - 1;
myArray = new T[sizeofarray];
for (size_t i = 0; i < sizeofarray; i++)
{
if (i < sizeofthis)
{
myArray[sizeofthis - 1 + i] =NULL;
}
myArray[i] = temp[i];
}
delete[] temp;
}
template<typename T>
inline T & DynamicArray<T>::at(int place)
{
return myArray[place];//return the element at place
}
template<typename T>
inline T & DynamicArray<T>::front()
{
return myArray[0];//return the first element in the array
}
template<typename T>
inline T & DynamicArray<T>::back()
{
return myArray[sizeofarray];//return the last element in the array
}
template<typename T>
inline T & DynamicArray<T>::operator[](int place)
{
return myArray[place];//return the element at place using subscript operator instead of dynarray.at()
}
template<typename T>
inline size_t DynamicArray<T>::capacity()
{
return back() - front();//
}
template<typename T>
inline size_t DynamicArray<T>::max_size()
{
return std::numeric_limits<T>::max();
}
template<typename T>
inline DynamicArrayIter<T> DynamicArray<T>::begin()
{
return DynamicArrayIter<T>(myArray);
}
template<typename T>
inline DynamicArrayIter<T> DynamicArray<T>::end()
{
return DynamicArrayIter<T>(myArray + sizeofarray - 1);
}
template<typename T>
inline void DynamicArray<T>::clear()
{
sizeofarray = 0;
myArray = new T[sizeofarray];
myArray[0] = NULL;
}
template<typename T>
inline int DynamicArray<T>::size()
{
return sizeofarray;
}
size() returns the number of elements that are held by the container while capacity is how many elements it can hold before more space must be allocated. So capacity can be greater than the size of the vector.
In your implementation, you have to create one more member capacity that will store the actual size of allocated array whereas size will hold the number of elements the container is holding.

Adding to dynamic array

Disclaimer: Yes, I know about std::vector. I'm doing this for the sake of learning.
I'm working on making a dynamic array class, and I'm trying to get add to work.
template <class T>
void Array<T>::add(T value)
{
T * tmp = new T[mCount];
for (int i = 0; i < mCount; i++)
{
tmp[i] = mData[i];
}
mCount++;
delete[] mData;
mData = tmp;
mData[mCount - 1] = value;
}
It works... sort of. The function works in adding the element, but then the program crashes when exiting. No errors, no nothing. It just freezes, and I have to close it using (Shift + F5).
So, what's wrong with this?
Here's my whole class. If I didn't include a function it means there's no code in it.
#ifndef ARRAY_H
#define ARRAY_H
using namespace std;
template <class T>
class Array
{
private:
T * mData;
int mCount;
public:
Array();
~Array();
void add(T value);
void insert(T value, int index);
bool isEmpty();
void display();
bool remove(T value);
bool removeAt(int index);
int size();
T & operator[](const int index);
};
// Constructors / Destructors
// --------------------------------------------------------
template <class T>
Array<T>::Array()
{
mCount = 0;
mData = new T[mCount];
for (int i = 0; i < mCount; i++)
mData[i] = 0;
}
template <class T>
Array<T>::~Array()
{
delete[] mData;
}
// General Operations
// --------------------------------------------------------
template <class T>
void Array<T>::add(T value)
{
T * tmp = new T[mCount];
for (int i = 0; i < mCount; i++)
{
tmp[i] = mData[i];
}
mCount++;
delete[] mData;
mData = tmp;
mData[mCount - 1] = value;
}
template <class T>
void Array<T>::display()
{
if (isEmpty())
{
cout
<< "The array is empty."
<< "\n\n";
return;
}
cout << "(";
for (int i = 0; i < mCount; i++)
{
cout << mData[i];
if (i < mCount - 1)
cout << ", ";
}
cout << ")" << "\n\n";
}
template <class T>
bool Array<T>::isEmpty()
{
return mCount == 0;
}
template <class T>
int Array<T>::size()
{
return mCount;
}
// Operator Overloads
// --------------------------------------------------------
template <class T>
T & Array<T>::operator[](const int index)
{
return mData[index];
}
#endif
If you need any additional info lemme know and I can post it.
Assuming mCount keeps the number of elements in the array, then when adding a new element you really have to allocate at least mCount + 1 elements (assuming of course you want to keep all the old ones and the new one) via:
T * tmp = new T[mCount + 1];
as opposed to:
T * tmp = new T[mCount];
If it's for anything else other than educational purposes, please use std::vector instead. For example your add function is not exception safe.

Array resize function in dynamic memory

I'm making a function to resize an array in dynamic memory and it's not working..
here's the code:
template <class Type>
void Array<Type>::Resize(int newSize)
{
if(newSize==size)
return;
if(newSize<=0)
return;
Type *temp = new Type[newSize];
int min=(newSize>size)?size:newSize;
for(int i=0; i<min; i++)
temp[i]=elements[i];
delete []elements;
elements = temp;
temp = NULL;
}
the problem is in these two statements
delete []elements;
elements = temp;
cause when i comment them the program works properly,
but it actually doesn't do what is supposed to do..
I think the problem is something that is being destroyed when getting out of the function scope and I have to call it by reference but I can't actually cause this is a member function.
Here's the whole header file:
#include<string>
#include<iostream>
using namespace std;
#ifndef ARRAY_H
#define ARRAY_H
template <class Type>
class Array
{
public:
Array (int s);
Array (const Array& obj);
~Array ();
const Array& operator= (const Array& obj);
Type GetElement (int index) const;
void SetElement (Type ele, int index);
void Resize (int newSize);
void Print () const;
void Destroy ();
private:
int size;
Type* elements;
};
template <class Type>
Array<Type>::Array(int s)
{
if(s<0)
return;
size=s;
elements = new Type[size];
}
template <class Type>
Array<Type>::Array(const Array &obj)
{
size = obj.size;
elements = new Type[size];
for(int i=0; i<size; ++i)
elements[i]=obj.elements[i];
}
template <class Type>
Array<Type>::~Array()
{
delete [] elements;
elements = NULL;
size = 0;
}
template <class Type>
void Array<Type>::Destroy()
{
delete [] elements;
elements = NULL;
size = 0;
}
template <class Type>
const Array<Type> &Array<Type>::operator=(const Array &obj)
{
if(this != &obj)
{
size = obj.size;
if(elements != NULL)
delete [] elements;
elements = new Type[size];
for(int i=0; i<size; i++)
elements[i] = obj.elements[i];
}
return *this;
}
template <class Type>
Type Array<Type>::GetElement(int index) const
{
if(index<0 || index>=size)
cout << "Sorry, this operation can not be proceeded \n";
else
return elements[index];
}
template <class Type>
void Array<Type>::SetElement(Type ele, int index)
{
if(index<0 || index>=size){
cout << "Sorry, this operation can not be proceeded \n";
return; }
else
elements[index] = ele;
}
template <class Type>
void Array<Type>::Print() const
{
for(int i=0;i<size; ++i)
cout << elements[i] << endl;
}
template <class Type>
void Array<Type>::Resize(int newSize)
{
if(newSize==size)
return;
if(newSize<=0)
return;
Type *temp = new Type[newSize];
int min=(newSize>size)?size:newSize;
for(int i=0; i<min; i++)
temp[i]=elements[i];
delete []elements;
elements = temp;
temp = NULL;
}
#endif
You forgot to do one thing in the Resize() function, and that is to update the member size with the new size after reallocation. This will cause it to access memory beyond the end of the buffer after a resize with a smaller new dimension, e.g.:
Array<int> arr(10);
// set the 10 values
arr.Resize(5);
// here the buffer will have 5 elements, but arr.size is still 10
arr.Print(); // this will read elements 0 - 9, not 0 - 4
Couple of observations
if(newSize==size)
size does not exist
delete []elements;
elements = temp;
You are attempting to copy to an array you have just deleted, which was never created in the first place.
What is meant by "does not work" and "the program works properly,"?