#include <iostream>
using namespace std;
template <typename T>
class DynamicArray
{
T *array;
unsigned int elements;
unsigned int size;
public:
void expand_array(int extra_size)
{
T *new_array= new T[size + extra_size];
//copy integers from old array
memcpy(new_array,array,elements*sizeof(T));
//make 0 the integers from new part of the array
memset(new_array + size, 0, extra_size * sizeof(T));
delete [] array;
array = new_array;
size += extra_size;
}
//constructors
DynamicArray()
{
array = new T[8];
elements = 0;
size = 8;
memset(array,0,size*sizeof(T));
}
DynamicArray(const unsigned int size)
{
array= new T[size];
}
virtual ~DynamicArray()
{
delete [] array;
}
void add(T new_element)
{
if(elements>=size)
expand_array(8);
array[elements++] = new_element;
}
int get (const unsigned int index) const
{
if(index< elements)
return array[index];
return -1;
}
void add(const unsigned int index, T new_element)
{
if(index>size)
expand_array(index- size +1);
array[index] = new_element;
elements = index +1;
}
DynamicArray &operator=(DynamicArray &ab)
{
elements=ab.elements;
size=ab.size;
if (this == &ab)
return *this;
delete array;
if(ab.array)
{
array= new T[size];
memcpy(array,ab.array,elements*sizeof(T));
}
else
{
array=0;
}
return *this;
}
DynamicArray(const DynamicArray& source)
{
elements=ab.elements;
size=ab.size;
if(ab.array)
{
array= new T[size];
memcpy(array,ab.array,elements*sizeof(T));
}
else
{
array=0;
}
}
};
int main()
{
DynamicArray<int> da(2);
DynamicArray<int> db(2);
DynamicArray< DynamicArray<int> > array_of_arrays(2);
array_of_arrays[0] = da;/
//array_of_arrays[1] = db;
/*
da[0]=5;
da[1]=2;
db[0]=3;
db[1]=4;
cout<<array_of_arrays[0][0]<<endl;
*/
system("color 0C");
system("pause");
return 0;
}
I need help in understanding why this gives me an error:
error C2676: binary '[' : 'DynamicArray<T>' does not define this operator or a conversion to a type acceptable to the predefined operator
i added this
T& operator[](unsigned int index)//important to provide this operator
{
if (index > size)
{
expand_array(index-size);
}
return array[index];
}
but subequently i got invalid allocation size error during runtime.I try to try it and figure that the problem is somewhere about this area
if(ab.array)
{
array= new T[size];
memcpy(array,ab.array,elements*sizeof(T));
}
but i have no idea why is that so.
Any ideas?
Thanks I figured it out: One of the attributes are not initialise to a proper valuein one of the constructors
DynamicArray(const unsigned int size)
.
Thanks for all the help.
The error has nothing to do with templates. The problem is that you use the [] operator on array_of_arrays. However the DynamicArray class does not define operator[].
What it does define is a method named add, so maybe you meant to call that instead? I.e. array_of_arrays.add(0, da); instead of array_of_arrays[0] = da;.
However it would probably be more idiomatic to simply define operator[] on your class.
DynamicArray does not define a subscript operator.
This would typically look like:
T& operator[] (unsigned int index)
{
if (index > size)
{
// Handle error
}
return array[index];
}
Related
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.
I'm trying to make my own vector in C++ so I could understand more how it works !
This is the code:
#pragma once
template<typename T>
class Vector {
public:
Vector() {
// allocate 2 elements
ReAlloc(2);
}
void pushBack(const T& value) {
if (m_Size >= m_Capacity) {
ReAlloc(m_Capacity / 2);
}
m_Data[m_Size++] = value;
}
const T& operator[](size_t index) const {
/*
if (index >= m_Size) {
// assert
}
*/
return m_Data[index];
}
T& operator[](size_t index) {
/*
if (index >= m_Size) {
// assert
}
*/
return m_Data[index];
}
const size_t Size() const { return m_Size; }
size_t Size() { return m_Size; }
private:
T* m_Data = nullptr;
size_t m_Size = 0;
size_t m_Capacity = 0;
private:
void ReAlloc(size_t newCapacity) {
// 1. allocate a new block of memory
// 2. copy/move old elements into the new block
// 3. delete the old one
T* newBlock = new T[newCapacity];
if (newCapacity < m_Size) {
m_Size = newCapacity;
}
for (size_t i = 0; i < m_Size; i++) {
newBlock[i] = m_Data[i];
}
delete[] m_Data;
m_Data = newBlock;
m_Capacity = newCapacity;
}
};
However, When I try to use it from main.cpp like this:
#include <iostream>
#include <string>
#include "Vector.h"
#define print(x) std::cout << x
#define println(x) std::cout << x << std::endl
template<typename T>
void PrintVector(Vector<T>& vector) {
for (size_t i = 0; i < vector.Size(); i++) {
println(vector[i]);
}
println("------------------------------------------");
}
int main() {
Vector<std::string> vector;
vector.pushBack("Ahmed");
vector.pushBack("C++");
vector.pushBack("Vector");
PrintVector(vector);
}
The code give me this output:
Ahmed
Vector
------------------------------------------
(process 7540) exited with code -1073740940.
it's not even printing C++ and the code acts weird, whenever I try o change anything the output became more mess, Could anyone tell me what did I do wrong please ?!.
Thx ! :)
In your pushBack function, when the size is greater than or equal to capacity, you are doing:
ReAlloc(m_Capacity / 2);
which doesn't make sense. If you need additional space to add elements, you should increase the capacity of the underlying array, not decrease it by half.
You are probably looking for:
ReAlloc(m_Capacity * 2);
which doubles the underlying capacity.
Here's a working demo, without any segfault.
I am trying to implement a template Array class that can hold pointers as well as primitive data types.
But when calling the destructor, the pointers in that array are not properly deleting.
So I am trying to convert each item in that array to its corresponding class and call delete. But I met with an issue. I'm not able to convert T type to my class pointer.
My intention is to delete items in that array. Can someone please help in this?
template <class T>
class LIBRARY_EXPORT MyArrayT
{
public:
MyArrayT()
{
this->count = 0;
}
~MyArrayT()
{
if ((this->count) > 0)
{
//std::cout << "Deleting Array values" << std::endl;
delete[] this->values;
//free(this->values);
/*for (int i = 0; i < this->count; i++)
{
delete this->values[i];
}*/
this->count = 0;
}
}
void SetValue(std::vector< T > items)
{
//Delete existing memory
delete[] this->values;
this->count = items.size();
if (this->count > 0)
{
this->values = new T[this->count];
for (int i = 0; i < count; i++)
{
this->values[i] = items[i];
}
}
}
void SetValue(T items, int index)
{
if (this->count > index)
{
this->values[index] = items;
}
}
T GetValue(int index)
{
if (this->count > index)
{
return this->values[index];
}
return NULL;
}
T* GetValue()
{
return this->values;
}
_int64 GetCount()
{
return this->count;
}
private:
_int64 count;
T* values;
};
class LIBRARY_EXPORT MyString
{
public:
MyString();
~MyString();
void SetValue(std::string str);
std::string GetValue();
_int64 GetCount();
private:
_int64 count;
char* value;
};
int main()
{
MyArrayT<MyString*>* MyArrayValue = new MyArrayT<MyString*>() ;
vector<MyString*> value9;
MyString* opt1 = new MyString();
opt1->SetValue("Option: 1");
value9.push_back(opt1);
MyArrayValue->SetValue(value9);
MyArrayT<int>* MyArrayValueInt = new MyArrayT<int>() ;
vector<int> value1;
value1.push_back(1);
value1.push_back(2);
MyArrayValueInt->SetValue(value1);
delete MyArrayValue; //Calling this delete doesn't calling the ~MyString() destructor
delete MyArrayValueInt;
}
can somebody ewxplain me how the compiler calls the operator casting:
operator ELEMENT()const {
return pArray->arr[index];
}
From line 6 in main:
(*ptr3)[0] = a1[0] + a2[1];
How adding two ELEMENT object with + operator even allowed? There is no + operator overloading in ELEMENT class.
Thanks,
Liron
#include <iostream>
using namespace std;
template<class ELEMENT> class Array
{
class Element
{
Array<ELEMENT>* pArray;
int index;
public:
Element(Array<ELEMENT>* p, int i)
: pArray(p), index(i) {}
const Element& operator=(const ELEMENT& e) {
pArray->set(index, e); // call copy-on-write
return *this;
}
operator ELEMENT()const {
return pArray->arr[index];
}
};
friend class Element;
ELEMENT* arr;
int size;
int* ref_counter;
void attach(const Array& a) {
arr = a.arr; size = a.size;
ref_counter = a.ref_counter;
++(*ref_counter);
}
void detach() {
if(--(*ref_counter) == 0) {
delete []arr;
delete ref_counter;
}
}
void set(int index, const ELEMENT& e) {
if(*ref_counter > 1) { // need copy-on-write!
Array temp = clone();
detach();
attach(temp);
}
arr[index] = e;
}
public:
explicit Array(int);
Array<ELEMENT> clone()const;
Array(const Array<ELEMENT>& a){attach(a);}
~Array(){detach();}
const Array& operator=(const Array<ELEMENT>& a) {
detach(); attach(a); return *this;
}
Element operator[](int index) {
return Element(this, index);
}
const ELEMENT& operator[](int index)const {
return arr[index];
}
};
template<class ELEMENT>
Array<ELEMENT>::Array(int size1)
: size(size1), ref_counter(new int(1))
{
arr = new ELEMENT[size];
}
template<class ELEMENT>
Array<ELEMENT> Array<ELEMENT>::clone()const {
Array temp(size);
for(int i=0; i<size; ++i) {
temp.arr[i] = arr[i];
}
return temp;
}
int main()
{
Array<int> a1(1), a2(2);
Array<int>* ptr3 = new Array<int>(3);
a2[0] = 1;
a2[1] = 2;
a1 = a2;
(*ptr3)[0] = a1[0] + a2[1];
(*ptr3)[1] = a1[1] + a2[0];
cout << (*ptr3)[0] << ", " << (*ptr3)[1] << endl;
delete ptr3;
return 1;
}
How adding two ELEMENT object with + operator even allowed? There is no + operator overloading in ELEMENT class.
ELEMENT is not a class, it's a type parameter. And in your example the type given for that parameter is int. Obviously int does have a + operator, so that works fine. If you tried to create an Array<SomeType> where SomeType did not have a + operator, you would get an error.
There is an Element class and that class does indeed have no + operator, but that class is implicitly convertible to ELEMENT (i.e. int in this case), so when you apply + to objects of the Element the compiler adds a call to that conversion operator and + is applied to the result.
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()
{
}