Dynamic Array resizing in C++ Doesn't work properly - c++

i have this reSize function in my Array header
void reSize(int newsize) {
T* old = items;
size = newsize;
items = new T[newsize];
for (int i = 0;i < length;i++)
items[i] = old[i];
delete[]old;
}
and my main code:
struct User{
string name;
Array<int> data;
};
int main() {
Array<User> x(3);
x.get(0).name = "Kmal";
x.get(0).data.push_back(2); x.get(0).data.push_back(3);
x.reSize(10);
cout << x.get(0).data.get(0) <<endl;
return 0;
}
the problem is after resizing, my values that were stored in "data" variable are gone.
when i commented the code.
//delete[] old
in the reSize function
it worked fine...so i guess the problem is when i delete the pointer it deletes also the pointer inside the struct object which i don't want it to happen..
i don't want to comment the command becuz a leak in the memory will happen...how to fix this problem ?.
Update: My Array Class .
#include <iostream>
using namespace std;
template <class T>
class Array {
private :
T* items;
int size;
int length;
public :
Array() {
this->size = 0;
items = new T[this->size];
length = 0;
}
Array(int size) {
this->size = size;
items = new T[this->size];
length = 0;
}
int getsize() {
return this->size;
}
template <class T> void push_back(T x) {
if ((length+1) <= size) {
items[length] = x;
length++;
}
else {
this->reSize(size+1);
items[length] = x;
length++;
}
}
template <class T> void Insert(int index, T x) {
if (length + 1 <= size) {
for (int i = length;i > index;i--) {
items[i] = items[i - 1];
}
items[index] = x;
length++;
}
else {
this->reSize(size+1);
for (int i = length;i > index;i--) {
items[i] = items[i - 1];
}
items[length] = x;
length++;
}
}
template <class T> int Find(T x) {
int index = -1;
for (int i = 0;i < length;i++) {
if (items[i] ==x) {
index = i;
break;
}
}
return index;
}
void remove(int index) {
items[index] = "";
if(index+1 < length)
for (int i = index;i < length-1;i++) {
items[i] = items[i + 1];
items[i + 1] = "";
}
length--;
}
void reSize(int newsize) {
T* old = items;
size = newsize;
items = new T[newsize];
for (int i = 0;i < length;i++)
items[i] = old[i];
delete[]old;
}
void Merge(Array<T> x){
T* old = items; int oldlength = length;
items = new T[size + x.size];
size = size + x.size;
length += x.length;
for (int i = 0;i < length;i++) {
if(i< oldlength)
items[i] = old[i];
else
items[i] = x.items[i-oldlength];
}
delete[] old;
}
T& get(int index) {
return items[index];
}
}

struct User{
string name;
Array<int> data;
};
int main() {
Array<User> x(3);
// this line causes some problems
x.get(0).name = "Kmal";
x.get(0).data.push_back(2); x.get(0).data.push_back(3);
x.reSize(10);
cout << x.get(0).data.get(0) <<endl;
return 0;
}
In your code, declaring Array<User> x(3) declares an empty array with 3 elements that are preallocated. The length property of the array is 0. When the array is copied, length(0) elements are copied over into the resized storage. When you access the 0th element, it won't be copied on resize. What you actually need to do is call push_back() to add an element to the array so that length becomes 1 and the element is copied on resize.
Also, your array class is lacking a proper copy constructor and move constructor, which means copying it won't work at all. This means that User cannot be copied properly since it contains an array, which means that resizing an array of User won't work. You need to implement a copy constructor and copy assignment operator to be able to copy the array. You also need a destructor since, right now, the array is leaking memory when it goes out of scope.

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;
}

I can't add a new element to dynamic array

There is something wrong with the expand() method.
#include <iostream>
struct obj
{
int fInt;
float fFloat;
};
template <typename T>
class dynamicArray {
private:
T* myArray;
int elements;
int size;
public:
dynamicArray();
void add(T dane);
void expand();
void init(int el);
T get(int index);
};
template <typename T>
dynamicArray<T>::dynamicArray()
{
this->size = 1;
this->elements = 0;
this->myArray = new T[this->size];
init(this->elements);
}
template <typename T>
T dynamicArray<T>::get(int index)
{
return this->myArray[index];
}
template <typename T>
void dynamicArray<T>::init(int el)
{
for (size_t i = el; i < this->size; i++)
{
this->myArray[this->elements] = nullptr;
}
}
template <typename T>
void dynamicArray<T>::expand()
{
this->size *= 2;
T* tempArr = new T[this->size];
for (int i = 0; i < this->elements; i++)
{
tempArr[i] = this->myArray[i];
//tempArr[i] = new T(*this->myArray[i]);
}
for (int i = 0; i < this->elements; i++)
{
delete this->myArray[i];
}
delete this->myArray;
this->myArray = tempArr;
init(this->elements);
}
template <typename T>
void dynamicArray<T>::add(T dane)
{
if (this->size == this->elements)
this->expand();
this->myArray[this->elements] = dane;
this->elements++;
}
int main()
{
dynamicArray<obj*>* arr = new dynamicArray<obj*>();
obj* so = new obj;
so->fInt = 2;
so->fFloat = 2;
arr->add(so);
obj* so2 = new obj;
so2->fInt = 3;
so2->fFloat = 3;
arr->add(so2);
so = arr->get(0);
so2 = arr->get(1);
std::cout << so->fInt << std::endl;
std::cout << so->fInt;
}
In this for loop I would like to assign to temporary array elements of myArray but they are not the copies
for (int i = 0; i < this->elements; i++)
{
tempArr[i] = this->myArray[i];
//tempArr[i] = new T(*this->myArray[i]);
}
and when I delete them they disappear from tempArr too.
for (int i = 0; i < this->elements; i++)
{
delete this->myArray[i];
}
I tried couple things but I can't find the solution.
tempArr[i] = new T(*this->myArray[i]);
I am not sure if this is the right track, but it's giving me a
'initializing': cannot convert from 'obj' to 'T'
and
'=' cannot convert from 'T*' to 'T'
You got yourself confused, you have a pointer to an array of T, not a pointer to an array of T*, but some of your code is written as if you had the latter.
This (in expand)
for (int i = 0; i < this->elements; i++)
{
delete this->myArray[i];
}
delete this->myArray;
should simply be
delete[] this->myArray;
You can't delete individual array elements because they are not (necessarily) pointers. And delete[] this->myArray; will invoke the destructor for all elements in your array.
And init can simply be deleted, because again it assumes that your array elements are pointers.
Try writing some code with dynamicArray<int>, so that your T is definitely not a pointer. That will find all the places where you've incorrectly assumed that T is a pointer (in case I've missed any).

Segmentation fault when using copy constructor C++

Everything seems to be copying fine, but when I call array2.print(), it shows segmentation fault. What am I doing wrong?
#include <iostream>
#include <initializer_list>
template <typename T>
class DynamicArray
{
private:
const int GROWTH_FACTOR = 2;
const int INITIAL_CAPACITY = 5;
T *m_array;
int m_capacity; // Capacity of the array
int m_size; // Number of added elements
public:
DynamicArray(std::initializer_list<T> elements)
: m_size(elements.size())
, m_capacity(elements.size() * 2)
{
m_array = new T[m_capacity];
std::copy(elements.begin(), elements.end(), m_array);
}
DynamicArray()
: m_size(0)
, m_capacity(INITIAL_CAPACITY)
{
m_array = new T[m_capacity];
}
~DynamicArray()
{
delete[] m_array;
}
DynamicArray(const DynamicArray& other)
: GROWTH_FACTOR(other.GROWTH_FACTOR)
, INITIAL_CAPACITY(other.INITIAL_CAPACITY)
, m_capacity(other.m_capacity)
, m_size(other.m_size)
{
T *m_array = new T[m_capacity];
std::copy(other.m_array, other.m_array + m_size, m_array);
}
int size()
{
return m_size;
}
int capacity()
{
return m_capacity;
}
void resize()
{
int new_capacity = m_capacity * GROWTH_FACTOR;
m_capacity = new_capacity;
T *temp = new T[new_capacity];
std::copy(m_array, m_array + m_capacity, temp);
delete[] m_array;
m_array = temp;
}
void deleteAt(int pos)
{
for (int i = pos; i < m_size - 1; i++)
{
(*this)[i] = (*this)[i + 1];
}
m_size--;
}
void insertAt(T value, int pos)
{
if (m_capacity == m_size)
{
resize();
}
for (int i = m_size - 1; i >= pos; i--)
{
(*this)[i + 1] = (*this)[i];
}
m_size++;
(*this)[pos] = value;
}
void append(T value)
{
insertAt(value, m_size);
}
void print() {
for (int i = 0; i < m_size; i++)
{
std::cout << (*this)[i] << ", ";
}
std::cout << std::endl;
}
T& operator[](int index)
{
if (index < 0 || index > m_size - 1)
{
throw std::invalid_argument("Index out of range!");
}
return m_array[index];
}
};
int main()
{
DynamicArray<int> array = { 1, 2, 3, 4 };
DynamicArray<int> array2 = array;
array2.print();
return 0;
}
The error is here
T *m_array = new T[m_capacity];
It should be
m_array = new T[m_capacity];
By declaring a new variable called m_array you hid the class member variable that you wanted to assign to. The technical name for this is shadowing, a good compiler would warn you about this.
You redeclare m_array in the cctor, which shadows the class member.

Why is the overloading operator "=" not working properly on my class for Dynamic Arrays? C++

I'm trying to work with dynamic arrays. When I try to overload the "=" operator it does not work. When debugging the file it doesn't execute the void function to overload the operator.
#include <iostream>
using namespace std;
class cppArray {
public:
cppArray(int size);
~cppArray();
int read(int index);
void write(int content, int index);
void operator=(cppArray& s);
int search(int target);
int size();
private:
int* myArray;
int arraySize;
};
cppArray::cppArray(int size) {
myArray = new int[size];
arraySize = size;
}
//delete the memory space assigned to myArray
cppArray::~cppArray() {
delete[] myArray;
myArray = 0;
}
int cppArray::read(int index) {
if (index < arraySize) {
return myArray[index];
}
else {
cout << "Out of range" << endl;
exit(1);
}
}
Here I'm trying to copy the content of the original array to an auxiliar one, and then redefine the size of the original array so I can add more content to the original array
void cppArray::write(int content, int index) {
if (index < arraySize) {
myArray[index] = content;
}
else {
cppArray auxArray(arraySize);
auxArray.myArray = myArray;
delete[] myArray;
arraySize = index + 1;
myArray = new int[arraySize];
myArray = auxArray.myArray;
myArray[index] = content;
}
}
I'm pretty sure this is wrong, but I can't figure out a way to overload it correctly
void cppArray::operator=(cppArray& s) {
delete[] s.myArray;
s.myArray = new int[arraySize];
for (int i = 0; i < arraySize; i++)
{
myArray[i] = s.myArray[i];
}
}
int cppArray::size() {
return arraySize;
}
int main(int argc, char** argv) {
cppArray dsArray(3);
dsArray.write(1, 0);
dsArray.write(2, 1);
dsArray.write(3, 2);
dsArray.write(4, 3);
for (int i = 0; i < dsArray.size(); i++) {
cout << dsArray.read(i) << "\t";
}
cout << endl;
return 0;
}```
Your implementation is almost correct, but you delete the wrong array. You should only modify *this object, and not s. Also, you should follow conventions, or people will be very surprised when using your class.
Here's corrected version:
//return *this - a very expected convention
cppArray& cppArray::operator=(const cppArray& s) {
// Make sure s is not modified ^^^^
if (this == &s) {
return *this; //protection against self writing, things would get bad if you did that
}
arraySize = s.arraySize; //copy size first
delete[] myArray; //delete array from this object
myArray = new int[arraySize]; //recreate array
for (int i = 0; i < arraySize; i++)
{
myArray[i] = s.myArray[i]; //no changes here
}
return *this;
}

c++ array class problems

Alright, so without going into detail on why I'm writing this class, here it is.
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
aType * Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
aType * Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
aType * Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
It is supposed to be a std::Vector type object, without all the bells and whistles.
Problem is, it doesn't seem to work.
I basically start by going
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
I get an Access Violation Reading Location error and it hits on the line
Array[_Count] = Item
in the Push_back function.
The problem seems to be that it's not treating the Array object as an array in memory.
I've spent time going through the code step by step, and I don't know what else to say, it's not operating right. I don't know how to word it right. I'm just hoping someone will read my code and point out a stupid mistake I've made, because I'm sure that's all it amounts to.
Update
So now I changed 3 initializations of Array in nArray(), nArray(int Count), and Resize(int newSize)
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
This is how my code was before. Anyway, the original problem was the fact that when I try to access a specific element in the array, it just accesses the first element, and it doesn't seem to add elements eather. It doesn't seem to be treating Array as an array.
int Resize(int newSize)
{
.
.
aType * Array = new aType[newSize*2];
At this point, instead of updating the member variable as you intended, you've actually created a local variable called Array whose value is discarded when you exit from Resize(). Change the line to
Array = new aType[newSize*2];
The same thing is happening in your constructors, they also need changing accordingly. Moreover, since the default constructor allocates an array, you should set the size members accordingly. You have too many of these: an array needs to keep track of current element count and maximum capacity, however you appear to have three members. What is the purpose of the third? Redundant information is bad, it makes code difficult to read and without a single point of truth it is easier to make mistakes.
With the code in Resize(), you can do better: the second copy is completely redundant.
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
Also, in
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
you need curly braces around body of the if(), just indentation on its own won't do the trick:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
{
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
You have a number of problems. At a guess, the one causing problems so far is that your default ctor (nArray::nArray()) defines a local variable named Array that it initializes, which leaves nArray::Array uninitialized.
Though you probably haven't seen any symptoms from it (yet), you do have at least one more problem. Names starting with an underscore followed by a capital letter (such as your _Size, _MaxSize, and _Count) are reserved for the implementation -- i.e., you're not allowed to use them.
The logic in your Resize also looks needlessly inefficient (if not outright broken), though given the time maybe it's just my brain not working quite right at this hour of the morning.
Your array is not initialized by the constructors and resize function (working on local vars instead).
And is there a reason you want to store instances of string and not pointers to string (string *) ?
I think the answer after the changes is in moonshadow's reply:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
This code will always return aType(), the last two lines will never be reached.
You might also want to check what happens if you start out with a default-constructed nArray. (Hint: you call Resize(_MaxSize); but what is the value of _MaxSize in this case?
Edit:
This outputs "asdf2" for me as it should be (with the initialization and the braces fixed):
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1) {
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
#include <string>
#include <iostream>
using namespace std;
int main()
{
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
}