C++ Memory leakage with Dynamic Arrays - c++

I had to build a dynamic array class from scratch myself, and I also tried to extend it with a (set like) function to add new elements into the array, it compiles well, but the program crashes, since it has some memory leakages.
Please try and help me, I'm on a short notice at school.
The array class
template <class T>
class Array
{
int n; /// size
T* data;
public:
explicit Array(int n): n(n) { adat=new T[n]; }
Array(const Array&);
Array& operator=(const Array&);
~Array();
T& operator[](int idx) { return data[idx]; }
int size() { return n; }
int lookfor(T);
void add(T);
void del();
};
DEFINITIONS
template <class T>
Array<T>::Array(const Array<T>& t)
{
n=t.n;
data=new T[n];
for (int idx=0; idx<n; ++idx)
data[idx]=t.data[idx];
}
/**
Operator=
*/
template <class T>
Array<T>& Array<T>::operator=(const Array<T>& t)
{
if (this==&t) return *this;
delete[] data;
n=t.n;
data=new T[n];
for (int idx = 0; idx < n; ++idx)
data[idx]=t.data[idx];
return *this;
}
/**
dtor
*/
template <class T>
Array<T>::~Array()
{
del();
}
This must be the wrong part
template <class T>
int Array<T>::lookfor(T el)
{
for(int idx = 0; idx < n; ++idx)
if(data[idx] == el)
return idx;
return -1;
}
/**
add
*/
template <class T>
void Array<T>::add(T el)
{
if(lookfor(elem) != -1)
{
T* temp = new T[n + 1];
for (int idx = 0; idx < n; ++idx)
temp[idx]=data[idx];
temp[n + 1] = el;
del();
data = temp;
++n;
}
}
template <class T>
void Array<T>::del()
{
for(int idx = 0; idx < n; ++idx)
delete data[idx];
delete[] data;
}
The code it fails with:
Control ctrl;
ctrl.add(new Room());
ctrl.add(new Room());
Control and Room are both subclasses of the array. Like Control : publicArray < Room* >

Get rid of the loop in del() that deletes all the data[idx] elements. data is not an array of pointers, it's an array of values of type T, so you can't delete them. Even if you make an array of pointers, these pointers came from the caller to add, and they're owned by that part of the program, not the Array class. You also don't want to delete all the old pointers when you add an element to the array, because the new data array still contains those pointers.
Calling delete on something that wasn't created using new results in undefined behavior, which is likely causing your crash.

Related

How to implement insert vector c++?

I have to implement a vector class with operator[], rule of 5, push_back, and insert.
template<class T>
class MyVector
{
private:
int size_;
int capacity_;
T* data;
public:
typedef T* it;
it begin();
it end();
void push_back(const T& value);
I started to create constructor, copy constructor, move constructor, copy assignment operator, move assignment operator.
I implemented the begin() and end() like this:
template<class T>
typename MyVector<T>::it MyVector<T>::begin()
{
return data;
}
template<class T>
typename MyVector<T>::it MyVector<T>::end()
{
return data + size();
}
I don't know how to implement push_back() and insert().
For push_back(), I thought about something like this:
void push_back(const T & v)
{
if (size_ < capacity_)
data [size_++] = v;
}
But for insert(), I have no idea.
Could you help me please to implement insert()?
Your push_back() is not implemented correctly. It needs to grow the array when the size_ is equal to the capacity_, to make room for the new value being pushed.
Likewise, your insert() also needs to grow the array, if needed. It can then figure out the index where the new value should go, shift all of the elements after that index up one slot in the array, and then assign the new value to the element at that index.
Try something like this:
template<class T>
void MyVector<T>::grow()
{
static const int delta = ...; // <-- use whatever value makes sense for your use case...
int new_cap = capacity_ + delta;
T* new_data = new T[new_cap];
for(int i = 0; i < size_; ++i) {
new_data[i] = std::move(data[i]);
}
delete[] data;
data = new_data;
capacity_ = new_cap;
}
template<class T>
void MyVector<T>::push_back(const T & v)
{
if (size_ == capacity_)
grow();
data[size_] = v;
++size_;
}
template<class T>
void MyVector<T>::insert(typename MyVector<T>::it pos, const T & v)
{
int index = pos - data;
if (index < 0 || index > size_)
return; // or throw...
if (size_ == capacity_)
grow();
for(int i = size_ - 1; i >= index; --i)
data[i+1] = data[i];
data[index] = v;
++size_;
}
Live Demo
For insert you must.
make room for the extra data. (as you also need to do in push_back/emplace_back).
move the current data from the insertion point to the new offset.
copy the inserted data in.

C++ reszing dynamic array works up to a certain number of elements, but at some point crashes with error (0XC0000005)

Sorry if this has been answered before. I searched for resizing dynamic arrays and all the advice seems to be use STL Vector, but I'm doing an assignment where the point is to make my own, minimal, vector template class.
My vector class needs to store a dynamic array of structs created from reading from an input file. One of the things it has to do is resize when full. It works up to a point - processes 5121 lines out of 52207 lines and then crashes with error "Process returned -1073741819 (0XC0000005)".
I've looked around and found that this is a memory allocation error. I'm very new to programming and C++, and I'm stumped as to what in my program is causing this. I assume it is in my resizing the array code. Any help would be greatly appreciated!
My vector template code:
#ifndef VECTOR_H
#define VECTOR_H
#include <iostream>
using namespace std;
template <class T>
class Vector {
public:
/// Constructor
Vector();
/// Copy constructor
Vector(const Vector<T>& otherVector);
/// Destructor
virtual ~Vector();
/// assignment operator
const Vector<T>& operator= (const Vector<T>&);
/// methods
void addElement(const T& newElement);
T getElement(int index) const;
int getLength() const;
protected:
int arraySize;
int length;
T *p;
};
template <class T>
Vector<T>::Vector()
{
arraySize = 10;
length = 0;
p = new T[arraySize];
}
template <class T>
Vector<T>::Vector(const Vector& otherObject)
{
arraySize = otherObject.arraySize;
length = otherObject.length;
p = new T[arraySize];
for(int i = 0; i < length; i++)
p[i] = otherObject.p[i];
}
template <class T>
Vector<T>::~Vector()
{
delete [] p;
}
template <class T>
const Vector<T>& Vector<T>::operator= (const Vector<T>& newVector)
{
if(this != &newVector)
{
delete [] p;
arraySize = newVector.arraySize;
length = newVector.length;
p = new T[arraySize];
for(int i = 0; i < length; i++)
p[i] = newVector.p[i];
}
return *this;
}
template <class T>
void Vector<T>::addElement(const T& newElement)
{
if(length == arraySize)
{
// create a new resized array
T *temp;
temp = new T[arraySize*2];
// copy elements of p into temp
for(int i = 0; i < length; i++)
{
temp[i] = p[i];
}
// delete p and create new p and set equal to temp
delete [] p;
arraySize *= 2; // set array size to double
p = new T[arraySize];
p = temp;
// delete temp array
delete [] temp;
// add new element and incerement length;
p[length] = newElement;
length++;
}
else
{
p[length] = newElement;
length++;
}
}
template <class T>
T Vector<T>::getElement(int index) const
{
return p[index];
}
template <class T>
int Vector<T>::getLength() const
{
return length;
}
#endif
You have an error in your resize logic. Its all well and good until you get here.
p = new T[arraySize];
p = temp;
delete [] temp;
You allocate a new array and then immediately have p point to the data pointed to by temp. And then you delete the data pointed by temp which is the same as p which means p points to freed memory; it is a dangling reference and it is undefined to access anything through p
However, it is simple to fix: remove the allocation and deletion, you only need the line with the assignment:
// p = new T[arraySize];
p = temp;
// delete [] temp;
You don't need new space for p, temp already got it. Just give it to p. And then you don't delete temp, because p is managing it.

Trying to create copy function in a vector class

I am working on implementing a vector class but cannot figure out how to write a function to copy one vector into another.
template <class T> class Vec {
public:
//TYPEDEFS
typedef T* iterator;
typedef const T* const_iterator;
typedef unsigned int size_type;
//CONSTRUCTOS, ASSIGNMENT OPERATOR, & DESTRUCTOR
Vec() {this->create(); }
Vec(size_type n, const T& t = T()) { this->create(n, t); }
Vec(const Vec& v) { copy(v); }
Vec& operator=(const Vec& v);
~Vec() { delete [] m_data; }
//MEMBER FUNCTIONS AND OTHER OPERATORS
T& operator[] (size_type i) { return m_data[i]; }
const T& operator[] (size_type i) const { return m_data[i]; }
void push_back (const T& t);
iterator erase(iterator p);
void resize(size_type n, const T& fill_in_value = T());
void clear() { delete [] m_data; create(); }
bool empty() const { return m_size == 0; }
size_type size() const { return m_size; }
//ITERATOR OPERATIONS
iterator begin() { return m_data; }
const_iterator begin() const { return m_data; }
iterator end() { return m_data + m_size; }
const_iterator end() const { return m_data + m_size; }
private:
//PRIVATE MEMBER FUNCTIONS
void create();
void create(size_type n, const T& val);
void copy(const Vec<T>& v);
//REPRESENTATION
T *m_data; //point to first location inthe allocated array
size_type m_size; //number of elements stored in the vector
size_type m_alloc; //number of array locations allocated, m_size <= m_alloc
};
//create an empty vector (null pointers everywhere)
template <class T> void Vec<T>::create() {
m_data = NULL;
m_size = m_alloc = 0; //no memory allocated yet
}
//create a vector with size n, each location having the given value
template <class T> void Vec<T>::create(size_type n, const T& val) {
m_data = new T[n];
m_size = m_alloc = n;
for (T* p = m_data; p != m_data + m_size; ++p)
*p = val;
}
//assign one vector to another, avoiding duplicate copying
template <class T> Vec<T>& Vec<T>::operator=(const Vec<T>& v) {
if (this != &v) {
delete [] m_data;
this -> copy(v);
}
return *this;
}
This is the first things I came up with:
template <class T> void Vec<T>::copy(const Vec<T>& v) {
m_size = m_alloc = v.size();
m_data = &v;
}
I got an error about incompatible types...OK, makes sense that they are incompatible. So I take out the 'const' and now it works.
template <class T> void Vec<T>::copy(Vec<T>& v) {
m_size = m_alloc = v.size();
m_data = &v[0];
}
I am guessing this isn't entirely correct or good form. I'm not sure. And now I get an error about the pointer being freed not having been allocated (but it compiles, runs, and copies the vector successfully at least now). So I would say I am not really understanding passing variables/arrays/vectors/things by reference, and also dynamic allocation of memory. My question is: how can I improve the copy function that I have written to either not compare two incompatible variables, or to successfully allocate the pointer dynamically to the new vector so that I don't get that malloc error?
You need to do deep-copy of the elements, not simply assign the pointer m_data:
// precondition: `m_data` is not allocated
template <class T> void Vec<T>::copy(const Vec<T>& v) {
m_data = new T[v.size()];
m_size = m_alloc = v.size();
for (size_t ii = 0; ii < m_size; ++ii)
m_data[ii] = v[ii];
}
For your copy-constructor to be safe it needs to fail when the copy can't be made.
Vec<T>::Vec(const Vec<T>& o):m_size(o.m_size), m_alloc(o.m_size), m_data(new T()){
std::copy( o.m_data, o.m_data+o.m_size, m_data);
}
The copy-constructor should be able to replace any Vec<T>::copy member.
The assignment is easily handled by introducing a swap function. This is exception safe.
void Vec<T>::swap(Vec<T>& rhs){
std::swap(m_data, rhs.m_data);
std::swap(m_size, rhs.m_size);
std::swap(m_capacity, rhs.m_capacity);
}
With the exception safe Copy & swap & idiom it becomes:
Vec<T>& Vec<T>::operator = (const Vec<T>& rhs){
Vec<T> cpy=rhs;
swap( this, cpy);
return *this;
}
Note that there is an issue with exception safety with the previous answer given. The simple fix is to allocate first.
// precondition: `m_data` is not allocated
template <class T> void Vec<T>::copy(const Vec<T>& v) {
m_data = new T[v.size()];
m_size = m_alloc = v.size();
for (size_t ii = 0; ii < m_size; ++ii)
m_data[ii] = v[ii];
}
The other issue with your code is operator=, which is not exception safe. You deleted m_data before allocating again with new[]. If new[] fails, you've corrupted your object.
Once you have the fix to copy as above, then operator = can be written in terms of the copy constructor:
template <class T> Vec<T>& Vec<T>::operator=(const Vec<T>& v)
{
// construct a temporary
Vec<T> temp = v;
// set the members
m_size = m_alloc = temp.size();
delete [] m_data;
m_data = temp.m_data;
// Now set temp.m_data to 0, so that destruction of temp doesn't delete
// our memory
temp.m_data = 0;
return *this;
}
Basically, we construct a temporary from v, delete the this->m_data and then assign the elements of temp to this. Then we remove the guts of temp by setting the temp.m_data data to NULL. This needs to be done so that when temp dies, we don't want to delete the data we assigned to this.
Note that if the first line Vec<T> temp = v; throws an exception, no harm to this is
done, thus exception safety is provided.
Here is the copy/swap idiom, as suggested by Captain Giraffe:
template <class T> class Vec {
//...
void swap(Vec<T>& left, Vec<T>& right);
//..
};
template <class T> void Vec<T>::swap(Vec<T>& left, Vec<T>& right)
{
std::swap(left.m_size, right.m_size);
std::swap(left.m_alloc, right.m_alloc);
std::swap(left.m_data, right.m_data);
}
template <class T> Vec<T>& Vec<T>::operator=(const Vec<T>& v)
{
// construct a temporary
Vec<T> temp = v;
swap(*this, temp);
return *this;
}
The difference here is that we're swapping the members of temp with this. Since temp will now contain the pointer that this used to have, when temp dies, it will be calling delete on this "old" data.

Trying to create resize function in a vector class

I was making a copy function here, got a lot of good answers, now moving on to a resize function. The Vec class I'm working on looks like this:
template <class T> class Vec {
public:
//TYPEDEFS
typedef T* iterator;
typedef const T* const_iterator;
typedef unsigned int size_type;
//CONSTRUCTOS, ASSIGNMENT OPERATOR, & DESTRUCTOR
Vec() {this->create(); }
Vec(size_type n, const T& t = T()) { this->create(n, t); }
Vec(const Vec& v) { copy(v); }
Vec& operator=(const Vec& v);
~Vec() { delete [] m_data; }
//MEMBER FUNCTIONS AND OTHER OPERATORS
T& operator[] (size_type i) { return m_data[i]; }
const T& operator[] (size_type i) const { return m_data[i]; }
void push_back (const T& t);
void swap(Vec<T>& left, Vec<T>& right);
iterator erase(iterator p);
void resize(size_type n, const T& fill_in_value = T());
void clear() { delete [] m_data; create(); }
bool empty() const { return m_size == 0; }
size_type size() const { return m_size; }
//ITERATOR OPERATIONS
iterator begin() { return m_data; }
const_iterator begin() const { return m_data; }
iterator end() { return m_data + m_size; }
const_iterator end() const { return m_data + m_size; }
private:
//PRIVATE MEMBER FUNCTIONS
void create();
void create(size_type n, const T& val);
void copy(const Vec<T>& v);
//REPRESENTATION
T *m_data; //point to first location inthe allocated array
size_type m_size; //number of elements stored in the vector
size_type m_alloc; //number of array locations allocated, m_size <= m_alloc
};
//create an empty vector (null pointers everywhere)
template <class T> void Vec<T>::create() {
m_data = NULL;
m_size = m_alloc = 0; //no memory allocated yet
}
//create a vector with size n, each location having the given value
template <class T> void Vec<T>::create(size_type n, const T& val) {
m_data = new T[n];
m_size = m_alloc = n;
for (T* p = m_data; p != m_data + m_size; ++p)
*p = val;
}
//assign one vector to another, avoiding duplicate copying
template <class T> Vec<T>& Vec<T>::operator=(const Vec<T>& v) {
Vec<T> temp = v;
swap(*this, temp);
return *this;
}
//swap one vector with another
template <class T> void Vec<T>::swap(Vec<T>& left, Vec<T>& right) {
std::swap(left.m_size, right.m_size);
std::swap(left.m_alloc, right.m_alloc);
std::swap(left.m_data, right.m_data);
}
This is what the resize function looks like so far:
template <class T> void Vec<T>::resize(size_type n, const T& fill_in_value) {
if (n<=m_size) { //if resize is smaller than original size, just resize
m_size = n;
}
else { //if resize is bigger, assign more space at the end and fill with a value
size_type temp = m_size;
m_size = n;
//for (T* p = m_data; p != m_data + temp; ++p) {
// std::cout << p << std::endl;
//}
//std::cout << std::endl;
for (T* p = &m_data[0] + temp; p != m_data + m_size; ++p) {
// std::cout << p << std::endl;
*p = fill_in_value;
}
}
}
When I use this in a program, I get a segmentation fault. I'm guessing there is something wrong with:
*p = fill_in_value
So I print out the values of p and it seems to give the appropriate number of spaces for whatever I put in (8 bits for a double, etc), so from the beginning of the vector there are exactly the number of spaces to resize and they all have the right number of bits. What is it that I am not understanding here?
EDIT: If I change it so that:
m_size = m_alloc = n;
does that mean that I am allocating new memory for the rest of the data? Or should I create a temporary vector with the new size and replace the existing vector with that? I don't really understand how to correct the issue that I am not truly resizing, but just accessing out of bounds. The way I am understanding it so far is that I change the size, add stuff to the memory addresses at the end, but leave the pointer to the first value the same (the name of the vector). This is not working, so I'm wondering what my conceptual misunderstanding is.
EDIT2: I've made this correction to the code based on the answers here and it works:
template <class T> void Vec<T>::resize(size_type n, const T& fill_in_value) {
if (n<=m_size) {
m_size = m_alloc = n;
}
else {
T* new_data = new T[n];
for (size_type i = 0; i < m_size; i++) {
new_data[i] = m_data[i];
}
for (size_type i = m_size; i < n; i++) {
new_data[i] = fill_in_value;
}
delete m_data;
m_data = new_data;
m_size = m_alloc = n;
}
}
You haven't actually allocated space for new elements. When new size is bigger than current, you should allocate new storage and copy existing elements there.
T* new_data = new T[n];
for ( size_type i = 0; i < m_size; ++i )
{
new_data[i] = m_data[i];
}
for ( size_type i = m_size; i < n; ++i )
{
new_data[i] = fill_in_value;
}
delete m_data;
m_data = new_data;
m_size = n;

c2955 Error - Use of Class template reuires argument list

So, I've tested vector and it seems to be running fine. However, I'm trying to implement a basic Stack class built off of my Vector class. I keep running into these errors when I go to build:
stack.h(4): error C2955: 'Vector' : use of class template requires template argument list
followed by:
vector.h(11) : see declaration of 'Vector'
stack.h(13) : see reference to class template instantiation 'Stack<T>' being compiled
Here is the Vector.h file:
#include<iostream>
using namespace std;
const int SIZEFACTOR = 4;
template <class T>
class Vector{
private:
unsigned int size_Of_Vector; // # of Items in list
unsigned int total_Vector_Capacity;//Total Capacity
T * vector_array;//Items themselves
public:
Vector();
~Vector();
void push_back(const T &e);
void pop_back();
bool empty();
int size() const;
void growVector();
void shrinkVector();
void shrinkToSize();
int currentCapacity() const;
//Operator
const T & operator [] (int index){
if((index >= size_Of_Vector) || index < 0){
cout << "ERROR! Index not used: " << index
<< " (max = " << size_Of_Vector << ")" << endl;
return EXIT_FAILURE;
}
return vector_array[index];
};//End Operator
};//End Header Definition
template <class T>
Vector<T>::Vector(){//Constructor
total_Vector_Capacity = 2;//Initially two items
size_Of_Vector = 0;//Nothing is in the vector yet
vector_array = new T [total_Vector_Capacity];//Initially two items
}
template <class T>
Vector<T>::~Vector (){//Destructor
total_Vector_Capacity = 0;
size_Of_Vector = 0;
delete [] vector_array;
}
template <class T>
void Vector<T>::growVector(){
total_Vector_Capacity = total_Vector_Capacity * SIZEFACTOR; //Quarter Size
//Temp Array
T * temp_array;
temp_array = new T [total_Vector_Capacity];
//Copy
for(unsigned int i = 0; i < size_Of_Vector; i++){
temp_array[i] = vector_array[i];
}
//Delete old array
delete [] vector_array;
//Re-initilize main array
vector_array = new T [total_Vector_Capacity];
//Copy old Data back to original array
for(unsigned int i = 0; i < size_Of_Vector; i++){
vector_array[i] = temp_array[i];
}
//Delete temp array
delete [] temp_array;
}
template <class T>
void Vector<T>::shrinkVector(){
total_Vector_Capacity = (int) (total_Vector_Capacity / SIZEFACTOR); //Quarter Size
//Temp Array
T * temp_array;
temp_array = new T [total_Vector_Capacity];
//Copy
for(unsigned int i = 0; i < size_Of_Vector; i++){
temp_array[i] = vector_array[i];
}
//Delete old array
delete [] vector_array;
//Re-initilize main array
vector_array = new T [total_Vector_Capacity];
//Copy old Data back to original array
for(unsigned int i = 0; i < size_Of_Vector; i++){
vector_array[i] = temp_array[i];
}
//Delete temp array
delete [] temp_array;
}
template <class T>
void Vector<T>::shrinkToSize(){
total_Vector_Capacity = size_Of_Vector; //Quarter Size
//Temp Array
T * temp_array;
temp_array = new T [total_Vector_Capacity];
//Copy
for(unsigned int i = 0; i < size_Of_Vector; i++){
temp_array[i] = vector_array[i];
}
//Delete old array
delete [] vector_array;
//Re-initilize main array
vector_array = new T [total_Vector_Capacity];
//Copy old Data back to original array
for(unsigned int i = 0; i < size_Of_Vector; i++){
vector_array[i] = temp_array[i];
}
//Delete temp array
delete [] temp_array;
}
template <class T>
void Vector<T>::push_back(const T &e){
if(size_Of_Vector == total_Vector_Capacity){//Resize if size equals capacity
cout << "\nGrow now\n";
growVector();
}
vector_array[size_Of_Vector]=e;
size_Of_Vector++;//Increase Vector Size
}
template <class T>
void Vector<T>::pop_back(){
if(size_Of_Vector == (int)(total_Vector_Capacity/SIZEFACTOR)){//Resize if size equals capacity
cout << "\nShrink now\n";
shrinkVector();
}
size_Of_Vector--;//Increase Vector Size
}
template <class T>
bool Vector<T>::empty(){
if(size_Of_Vector==0){
return true;
}
else{
return false;
}
}
template <class T>
int Vector<T>::size() const{
return size_Of_Vector;
}
template <class T>
int Vector<T>::currentCapacity() const{
return total_Vector_Capacity;
}
and stack.h:
template <class T>
class Stack : public Vector{
private:
Vector<T> stack;
public:
Stack(){};
void push(T x) {stack.push_back(&x)};
void pop(){stack.pop_back()};
bool empty(){stack.empty()};
};
You have defined Vector<T> as a member of Stack already, it's not necessary to inherit from Vector
Update
template <class T>
class Stack : public Vector{
//...
};
To:
template <class T>
class Stack {
Vector<T> stack;
//...
};
Or if you want to inherit from a template class, you need to provide template parameter
template <class T>
class Stack : public Vector<T>{
// ^^^
Note:
You miss a few semicolons in Stack function definition and a bug in Stack::push_back as well, I may suggest update to below:
template <class T>
class Stack
{
private:
Vector<T> stack;
public:
Stack(){};
void push(T const& x) {stack.push_back(x);}
void pop(){stack.pop_back();}
bool empty(){return stack.empty();}
};