Dynamic Array - Finding Capacity - c++

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.

Related

Dynamic array implementaion c++ , Overloading assignment operator

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;

What have I missed, what cause the memory leak C++

I'm having problem understanding where my memory leak is located in my project.
The template I have built looks like this:
#pragma once
#include "IHeap.h"
#include <iostream>
using namespace std;
template <typename T>
class dHeap
{
public:
dHeap(T size);
dHeap(T size, int nr);
dHeap(const dHeap &original);
~dHeap();
dHeap<T>& operator=(const dHeap<T> &original);
void deepCopy(const dHeap &original);
void push(const T &item);
T pop();
T peek()const;
int size()const;
int getdValue()const;
void printAll()const;
void heapify(int arr[], int size, int root);
void heapSort(int arr[], int size);
private:
//T nr;
T *arrHeap;
T nrOfItems;
T capacity;
T dValue;
void expandHeap();
};
template<typename T>
inline dHeap<T>::dHeap(T size)
{
capacity = size;
arrHeap = new T[capacity + 1];
nrOfItems = 0;
dValue = size;
}
template<typename T>
inline dHeap<T>::dHeap(T size, int nr)
{
capacity = size;
arrHeap = new T[nr];
nrOfItems = 0;
dValue = size;
}
template<typename T>
inline dHeap<T>::dHeap(const dHeap &original)
{
this->deepCopy(original);
}
template<typename T>
inline dHeap<T>::~dHeap()
{
delete[] arrHeap;
}
template<typename T>
inline dHeap<T>& dHeap<T>::operator=(const dHeap<T>& original)
{
if (this != &original)
{
this->deepCopy(original);
}
return *this;
}
template<typename T>
inline void dHeap<T>::expandHeap()
{
capacity *= 2;
T *temp = new T[capacity];
for (int i = 0; i < nrOfItems; i++)
{
temp[i] = arrHeap[i];
}
delete[] arrHeap;
arrHeap = temp;
}
template<typename T>
inline void dHeap<T>::deepCopy(const dHeap &original)
{
capacity = original.capacity;
nrOfItems = original.nrOfItems;
arrHeap = new T[capacity];
dValue = original.dValue;
for (int i = 0; i < original.nrOfItems; i++)
{
this->arrHeap[i] = original.arrHeap[i];
}
}
template<typename T>
inline void dHeap<T>::push(const T &item)
{
if (nrOfItems >= capacity)
{
expandHeap();
}
arrHeap[nrOfItems] = item;
nrOfItems++;
}
template<typename T>
inline T dHeap<T>::pop()
{
int removed = arrHeap[0];
arrHeap[0] = arrHeap[nrOfItems - 1];
nrOfItems--;
return removed;
}
template<typename T>
inline T dHeap<T>::peek() const
{
return arrHeap[0];
}
template<typename T>
inline int dHeap<T>::size() const
{
return this->nrOfItems;
}
template<typename T>
inline int dHeap<T>::getdValue() const
{
return this->dValue;
}
template<typename T>
inline void dHeap<T>::printAll() const
{
for (int i = 0; i < nrOfItems; i++)
{
cout << "Heap element " << i << ". " << arrHeap[i] << endl;
}
}
template<typename T>
inline void dHeap<T>::heapSort(int arr[], int size)
{
for (int j = 0; j < size; j++)
{
// Build heap - which means rearrange array
for (int i = size / 2 - 1; i >= 0; i--)
{
heapify(arrHeap, size, i);
}
for (int i = size - 1; i >= 0; i--)
{
swap(arrHeap[0], arrHeap[i]);
heapify(arrHeap, i, 0);
}
//when re-structured heap, use pop and re-do it again until done
arr[j] = pop();
}
}
template<typename T>
inline void dHeap<T>::heapify(int arr[], int n, int root)
{
int largest = root;
int leftChild = 2 * root + 1;
int rightChild = 2 * root + 2;
// If left child is larger than root
if (leftChild < n && arr[leftChild] > arr[largest])
{
largest = leftChild;
}
// If right child is larger than largest so far
if (rightChild < n && arr[rightChild] > arr[largest])
{
largest = rightChild;
}
// If largest is not root, heapify recursivly until done
if (largest != root)
{
swap(arr[root], arr[largest]);
heapify(arr, n, largest);
}
}
I have a pointer called heapArr which I use to build up a heap. When the program terminates the destructor is called and there have I put a delete[] this->heapArr declaration to remove the pointer when program is done.
And I have also added a delete[] this->heapArr in the expand function in order to free the memory before allocation the new expanded array.
I'm not sure I explained this perfectly but the problem is that I seem to miss to remove something because I get a memory leak warning when I end the program.
What have I missed?
Memory leaks in deepCopy, where you allocate new memory without de-allocating the old.
That being said, don't allocate memory yourself. A good chunk of your code is duplicating the functionality of std::vector, so use std::vector<T> instead of T*.
(If for some reason you cannot use std::vector I would recommend you implement a replacement. Divide-and-conquer by splitting memory management from the heap logic.)

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).

List Class filled with pointers losing adresses on return

I have a class called DiGraph, that contains an array to Node pointers:
DiGraph::DiGraph(int Size) : count(0){
nodes = new Node *[Size];
}
Now I want to define the function getNodes() which is essentially supposed to return the array in list form:
Liste<Node*> DiGraph::getNodes() {
Liste<Node*> nlist(count+1);
for (int i = 0; i < count; i++) {
nlist.append(nodes[i]);
}
return nlist;
}
At the end of the function the nlist is filled correctly but somehow the resulting copy at the function call does not contain the correct pointers but all other variables.
DiGraph a(6);
a.addNode(new Node("A", 50, 50));
Liste<Node*> gN = a.getNodes(); //gN does not contain the same pointers that were returned
The class 'Liste' is basically a dynamic array with templates and some fancy functions.
Now I think the answer is probably gonna be that nlist gets destroyed after the function ends but the pointers still remain valid in the nodes variable so why does the copy contain invalid ones?
EDIT
This is the list class:
#ifndef _LISTE_H
#define _LISTE_H
// -------------------------------------------------------------------
template <typename T>
class Liste {
private:
T *_values;
int _last;
int _size;
bool isFull();
int find(T value);
void increase();
void decrease();
public:
Liste(int size = 8);
Liste(Liste &list);
~Liste();
void append(T value);
void remove(T value);
T getValueAt(int pos);
int size();
T operator[](int pos);
};
// -------------------------------------------------------------------
template <typename T>
Liste<T>::Liste(int size) {
_size = size;
_last = 0;
_values = new T[size];
}
template <typename T>
Liste<T>::Liste(Liste &list) {
_size = list._size;
_last = list._last;
_values = list._values;
}
// -------------------------------------------------------------------
template <typename T>
Liste<T>::~Liste() {
delete[] _values;
}
// -------------------------------------------------------------------
template <typename T>
void Liste<T>::increase() {
T *tmp = new T[_size * 2];
for (int i = 0; i < _size; i++)
tmp[i] = _values[i];
delete[] _values;
_values = tmp;
_size *= 2;
}
// -------------------------------------------------------------------
template <typename T>
void Liste<T>::decrease() {
_size /= 2;
T *tmp = new T[_size];
for (int i = 0; i < _size; i++)
tmp[i] = _values[i];
delete[] _values;
_values = tmp;
}
// -------------------------------------------------------------------
template <typename T>
bool Liste<T>::isFull() {
return _last == _size;
}
// -------------------------------------------------------------------
template <typename T>
int Liste<T>::find(T val) {
int pos;
for (pos = 0; pos < _last; pos++)
if (_values[pos] == val)
return pos;
return -1;
}
// -------------------------------------------------------------------
template <typename T>
T Liste<T>::getValueAt(int pos) {
if (pos < 0 || pos >= _last)
throw "OutOfBoundsException";
return _values[pos];
}
// -------------------------------------------------------------------
template <typename T>
void Liste<T>::append(T val) {
if (isFull())
increase();
_values[_last] = val;
_last += 1;
}
// -------------------------------------------------------------------
template <typename T>
void Liste<T>::remove(T val) {
int pos = find(val);
if (pos == -1)
throw "ValueNotFoundException";
for (; pos < _last - 1; pos++)
_values[pos] = _values[pos + 1];
_last -= 1;
if (_last < _size / 4)
decrease();
}
// -------------------------------------------------------------------
template <typename T>
int Liste<T>::size() {
return _last;
}
// -------------------------------------------------------------------
template <typename T>
T Liste<T>::operator[](int pos) {
return getValueAt(pos);
}
#endif
template <typename T>
Liste<T>::Liste(Liste &list) {
_size = list._size;
_last = list._last;
_values = list._values;
}
What this code does is make the new Liste object (constructed from the copy constructor) point to the memory address of an existing Liste object. But this object will be destroyed so you get a dangling pointer. You need to perform a hard copy of the values.
template <typename T>
Liste<T>::Liste(const Liste &list) { // <--- const
_size = list._size;
_last = list._last;
_values = new T[_size];
for( std::size_t iter = 0 ; iter < _size ; ++iter )
{
_values[iter] = list._values[iter];
}
}
It is good modern practice to wrap pointer members to a smart pointer (eg unique_ptr<>). This way you will never forget to delete everything and object hold is guaranteed to be cleaned up even in a case of an incomplete constructor (exception thrown).
If you plan to return-by-value you should research into how to make your Liste class move-aware
Your T operator[](int pos); could also return a contained item by reference to allow immediate modification of the object ( T& operator[](int pos); ) cause, as it is, it returns a copy of the object that lies at _values[pos] and is most likely not what you want. Similarly for your T getValueAt(int pos); public method.

HEAP CORRUPTION DETECTED : after normal block ()

So, I've defined template class and then i tried to overload some operators.
template <typename T> class Set
{
public:
Set(void);
Set(Set&);
~Set(void);
bool contains(T elem);
bool add(T elem);
bool remove(T elem);
bool add(T* tab, int size);
T* getSet();
int size();
Set<T> &operator+(Set<T> &snd);
Set<T> &operator-(Set<T> &snd);
private:
T *elements;
int numOfElem;
};
When I try to add element to the Set by add method everything works fine.
template<typename T>
bool Set<T>::add(T elem)
{
bool found = false;
for(int i =0; !found && i<numOfElem; i++){
if(elem == elements[i]) found = true;
}
if( !found ){
numOfElem++;
T* tmp = new T[numOfElem];
for(int i =0; i<numOfElem-1; i++){
tmp[i] = elements[i];
}
tmp[numOfElem-1] = elem;
delete[] elements;
elements = tmp;
}
return !found;
}
template<typename T>
bool Set<T>::add(T* myArray, int size)
{
bool result = false;
for(int i =0; i<size; i++){
add(myArray[i]);
}
return result;
}
template<typename T>
Set<T>& Set<T>::operator+(Set<T> &snd)
{
Set *temp = new Set(*this);
temp->add(snd.getSet(), snd.size());
return *temp;
}
template<typename T>
void Set<T>::operator=(Set<T> &snd)
{
numOfElem = snd.numOfElem;
elements = new T[numOfElem];
for(int i =0; i < numOfElem; i++){
elements[i] = snd.elements[i];
}
}
template<typename T>
int Set<T>::size()
{
return numOfElem;
}
template<typename T>
T* Set<T>::getSet()
{
return elements;
}
template<typename T>
Set<T>::Set()
{
numOfElem = 0;
elements = nullptr;
}
template<typename T>
Set<T>::Set(Set& old)
{
numOfElem = old.numOfElem;
elements = new T(numOfElem);
for(int i = 0; i< numOfElem; i++){
elements[i] = old.elements[i];
}
}
template<typename T>
Set<T>::~Set()
{
numOfElem = 0;
delete[] elements;
elements = nullptr;
}
But if I use + operator instead (adding two separate sets) the error occurs while trying to delete the array (15 Line). Any ideas?
int main(){
Set <char> set1, set2, set3;
char tab[] = {'a','d','f','g'} ;
set1.add(tab, 4);
char tab2[] = {'a','d','x','y','z'} ;
set2.add(tab2,5);
set3= set1+set2;
}
You have a mistake in your copy constructor:
elements = new T(numOfElem);
It should be
elements = new T[numOfElem];
By writing new T(numOfElem); you allocate only one variable with its value initialized to numOfEllem.
Use a std::vector instead of the array and you will avoid such problems.
Your code is also leaking a memory in the addition operator:
template<typename T>
Set<T>& Set<T>::operator+(Set<T> &snd)
{
Set *temp = new Set(*this);
temp->add(snd.getSet(), snd.size());
return *temp;
}
You are allocating a memory and you never delete it so if you call that function too often you program may run out of its virtual memory and will crash with the uncaught std::bad_alloc exception. Change the function to this:
template<typename T>
Set<T> Set<T>::operator+(Set<T> &snd)
{
Set temp(*this);
temp.add(snd.getSet(), snd.size());
return temp;
}