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).
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've got two classes (structs) - Editor and Matrix. The matrix itself is working fine. But if I want to use Matrix via Editor, it's not working. I believe there is some problem with memory because I can't deallocate and even use matrix inside the Editor struct. I've tried to allocate the matrix dynamically, but then I couldn't use the addRow method.
Not really good with c++, but have to use those classes, can't use std::vector and stuff like that.
Editor definition:
struct Editor
{
private:
Matrix<std::string> data;
public:
Editor();
Editor(Matrix<std::string> oldData);
~Editor();
void addRow(std::string* row);
int getNumberOfRows();
int getNumberOfColumns();
};
Editor implementation:
using namespace std;
Editor::Editor()
{
}
Editor::Editor(Matrix<string> oldData)
{
data = oldData;
}
Editor::~Editor()
{
}
void Editor::addRow(std::string* row)
{
data.addRow(row);
}
int Editor::getNumberOfRows()
{
return this->data.getNumberOfRows();
}
int Editor::getNumberOfColumns()
{
return this->data.getNumberOfColumns();
}
Matrix definition:
template<typename T>
struct Matrix
{
private:
T** data;
int numberOfRows;
int numberOfColumns;
public:
Matrix(int numberOfRows, int numberOfColumns);
Matrix(const Matrix<T>& m);
~Matrix();
int getNumberOfRows();
int getNumberOfColumns();
T getItem(int indexRow, int indexColumn) const;
void addRow(T* newRow);
T** getData();
};
Matrix implementation:
template<typename T>
inline Matrix<T>::Matrix(int numberOfRows, int numberOfColumns)
{
this->numberOfColumns = numberOfColumns;
this->numberOfRows = numberOfRows;
this->data = new T * [numberOfRows];
for (int i = 0; i < this->numberOfRows; i++)
{
this->data[i] = new T[numberOfColumns];
}
}
template<typename T>
inline Matrix<T>::Matrix(const Matrix<T>& m)
{
numberOfRows = m.numberOfRows;
numberOfColumns = m.numberOfColumns;
if (m.data)
{
data = new T * [numberOfRows];
for (int i = 0; i < numberOfRows; i++)
data[i] = new T[numberOfColumns];
for (int i = 0; i < numberOfRows; i++)
{
for (int j = 0; j < numberOfColumns; j++)
{
data[i][j] = m.data[i][j];
}
}
}
}
template<typename T>
inline Matrix<T>::~Matrix()
{
for (int i = 0; i < this->numberOfRows; i++)
{
delete[] data[i];
}
delete[] data;
}
template<typename T>
inline int Matrix<T>::getNumberOfRows()
{
return this->numberOfRows;
}
template<typename T>
inline int Matrix<T>::getNumberOfColumns()
{
return this->numberOfColumns;
}
template<typename T>
inline T** Matrix<T>::getData()
{
return this->data;
}
template<typename T>
inline T Matrix<T>::getItem(int indexRow, int indexColumn) const
{
if (indexRow < 0 || indexRow > numberOfRows || indexColumn < 0 || indexColumn > numberOfColumns)
{
throw std::exception("not valid at least one of those indexes");
}
return this->data[indexRow][indexColumn];
}
template<typename T>
inline void Matrix<T>::addRow(T* newRow)
{
if (newRow == nullptr)
{
throw std::exception("not valid row");
}
T** newData = new T * [numberOfRows + 1];
for (int i = 0; i < numberOfRows + 1; i++)
{
newData[i] = new T[numberOfColumns];
for (int j = 0; j < numberOfColumns; j++)
{
if (i != this->numberOfRows)
{
newData[i][j] = data[i][j];
}
else {
newData[i][j] = newRow[j];
}
}
}
for (int i = 0; i < this->numberOfRows; i++)
{
delete[] this->data[i];
}
delete[] this->data;
this->data = newData;
this->numberOfRows++;
}
Main:
using namespace std;
int main()
{
Matrix<string> mt{1,1};
string* st = new string[3];
st[0] = "aa";
st[1] = "bb";
st[2] = "cc";
mt.addRow(st); // works
Editor ed{ mt };
ed.addRow(st); // doesn't work
return 0;
}
It crashes in xstring* on this:
_CONSTEXPR20_CONTAINER void _Copy_assign(const basic_string& _Right, false_type) {
_Pocca(_Getal(), _Right._Getal());
assign(_Right._Mypair._Myval2._Myptr(), _Right._Mypair._Myval2._Mysize);
}
with code:
Exception: Read access violation.
_Right – 0xDDDDDDDD.
EDIT:
Did cut most of the stuff from the project to just show the minimum. Anyway, the answer with semi-shallow copy was the right. Altho I thought
struct = struct;
calls for copy constructor. But it seems that it doesn't. I had to add operator= to somehow make it work properly.
I tried to make a dynamic array that adds elements at the beginning of the array. It works just fine with int, but when i try double, it gives me the error Process returned -1073741819 (0xC0000005). Debugging it works perfectly and all are in range, but when i run it crashes.
This is the header:
#define DYNAMICARRAY_H
#include <cstddef>
template <class T>
class DynamicArray
{
public:
DynamicArray();
DynamicArray(size_t);
DynamicArray(const DynamicArray&);
virtual ~DynamicArray();
DynamicArray& operator=(const DynamicArray&);
T &operator[] (size_t);
void add(T element);
size_t getCapacity();
size_t getLength();
bool isEmpty();
void print();
void resizeArr();
protected:
private:
T *arr;
size_t capacity;
size_t length;
};
#endif // DYNAMICARRAY_H
This is the .cpp
#include "DynamicArray.h"
#include <iostream>
template <class T>
DynamicArray<T>::DynamicArray()
{
length = 0;
capacity = 1;
arr = (T*)malloc(capacity * sizeof(arr));
if(!arr){
throw std::bad_alloc();
}
}
template <class T>
DynamicArray<T>::DynamicArray(size_t newSize)
{
length = 0;
capacity = newSize;
arr = (T*)malloc(capacity * sizeof(arr));
if(!arr){
throw std::bad_alloc();
}
}
template <class T>
DynamicArray<T>::~DynamicArray()
{
delete[] arr;
delete arr;
delete &capacity;
delete &length;
}
template <class T>
DynamicArray<T>::DynamicArray(const DynamicArray& other)
{
length = other.length;
capacity = other.capacity;
arr = (T*)malloc(capacity * sizeof(arr));
if(!arr){
throw std::bad_alloc();
}
for(size_t i = 0; i < length; i++){
arr[i] = other.arr[i];
}
}
template <class T>
DynamicArray<T>& DynamicArray<T>::operator=(const DynamicArray& rhs)
{
if (this == &rhs){
return *this;
}
delete[] arr;
length = rhs.length;
capacity = rhs.capacity;
arr = (T*)malloc(capacity * sizeof(arr));
if(!arr){
throw std::bad_alloc();
}
for(size_t i = 0; i < length; i++){
arr[i] = rhs.arr[i];
}
return *this;
}
template <class T>
size_t DynamicArray<T>::getLength()
{
return length;
}
template <class T>
size_t DynamicArray<T>::getCapacity()
{
return capacity;
}
template <class T>
bool DynamicArray<T>::isEmpty(){
return length == 0;
}
template <class T>
T &DynamicArray<T>::operator[] (size_t index)
{
if(index >= length){
std::cout << "Array index out of bounds" << "\n";
exit(0);
}
return arr[index];
}
template <class T>
void DynamicArray<T>::add(T element)
{
if(length >= capacity){
resizeArr();
}
if(!isEmpty()){
for(size_t i = length; i > 0; i--){
arr[i] = arr[i-1];
}
}
arr[0] = element;
length ++;
}
template <class T>
void DynamicArray<T>::print()
{
if(length == 0){
std::cout << "The array is empty!";
}
else{
for(size_t i = 0; i < length; i++){
std::cout << arr[i] << " ";
}
}
std::cout << "\n";
}
template <class T>
void DynamicArray<T>::resizeArr(){
size_t newCapacity = capacity * 2;
T *arr2 = (T*)realloc(arr, newCapacity * sizeof(arr));
if(!arr2){
std::cout << "Bad memory allocation";
throw std::bad_alloc();
}
arr = arr2;
capacity = newCapacity;
}
template class DynamicArray<double>;
template class DynamicArray<int>;
And the main
#include "DynamicArray.h"
#include <cstdlib>
#include <time.h>
#include <cstddef>
using namespace std;
int main()
{
srand (time(NULL));
DynamicArray<int> d(5);
int randomInt;
for(size_t i = 0; i < d.getCapacity(); i++){
randomInt = rand()% 100;
d.add(randomInt);
}
d.print();
d.add(5);
d.add(55);
d.add(3);
d.add(33);
d.add(37);
d.print();
delete &d;
cout << "\n\n";
DynamicArray<double> d2(5);
double randomDouble;
for(size_t i = 0; i < d2.getCapacity() - 3; i++){
//randomDouble = (double)rand() / ((double)RAND_MAX);
randomDouble = 0.5f;
d2.add(randomDouble);
d2.print();
}
d2.print();
return 0;
}
It crashes at the second for in the main, I've tried to make sure everything it set correctly, but still won't work:
for(size_t i = 0; i < d2.getCapacity() - 3; i++){
//randomDouble = (double)rand() / ((double)RAND_MAX);
randomDouble = 0.5f;
d2.add(randomDouble);
d2.print();
}
arr = (T*)malloc(capacity * sizeof(arr));
delete[] arr;
delete arr;
delete &capacity;
delete &length;
delete &d;
You pass pointers to delete[] and delete that were not returned from new[] or new respectively. Behaviour of the program is undefined. Relevant language rule:
[expr.delete]
... In a single-object delete expression, the value of the operand of delete may be a null pointer value, a pointer to a non-array object created by a previous new-expression, or a pointer to a subobject representing a base class of such an object. If not, the behavior is undefined. In an array delete expression, the value of the operand of delete may be a null pointer value or a pointer value that resulted from a previous array new-expression.
If not, the behavior is undefined. ...
Every delete expression of your program violate this rule.
To fix this, you must consistently use free on memory allocated with malloc, realloc or strdup, and use delete with pointers allocated with new, delete[] with pointers allocated with new[], absolutely no deallocation functions with pointers to non-dynamic objects such as member variables or objects with automatic or static storage duration, (or invalid pointers).
arr = (T*)malloc(capacity * sizeof(arr));
sizeof(arr) is the same as sizeof(T*) which isn't what you want, I suppose.
This should rather be sizeof(*arr) or sizeof(T).
Apart from that, don't mix malloc/delete or new/free, as others already pointed out.
If you're doing C, use malloc/free, and if you're in C++ use new/delete.
Using new would change the above to
arr = new T[capacity];
avoiding the whole sizing altogether.
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;
}
why that does not compile?
template <typename T>
class Pool{
char Buff[sizeof(T)*256];
public:
Pool(){
T* item = reinterpret_cast<T*>(&Buff[0]);
for(int i =0 ; i<256;i++)
item[i] = new(&item[i]) T();
}
~Pool(){
T* item = reinterpret_cast<T*>(&Buff[0]);
for(int i =0 ; i<256;i++)
item[i] -> ~ T();
}
void reset(unsigned int i){
T* item = reinterpret_cast<T*>(&Buff[0]);
item[i]->~T();
item[i]->T();
}
}
What i obviously want to achieve is calling placement new on a raw memory array (that should call constructor ok). Then I want to call destructor and constructor of items in the array. The problem is that Item is template and so if I use
Pool<FooBar>
the compiler expect to find "FooBar()" and "~FooBar()" instead of "T()" and "~T()".
is there any particular syntax to do that?
I'm using C++03 not C++11
Your syntax isn't quite right. The following should do the trick:
Pool() {
T* item = reinterpret_cast<T*>(&Buff[0]);
for(int i = 0; i < 256; i++)
new(&item[i]) T();
}
~Pool() {
T* item = reinterpret_cast<T*>(&Buff[0]);
for (int i = 0; i < 256; i++)
item[i].~T();
}
void reset(unsigned int i) {
T* item = reinterpret_cast<T*>(&Buff[0]);
item[i].~T();
new(&item[i]) T();
}