I tried to implement my own class named Array that act mostly like a vector because I don't want to use std. It works well with basic classes but when I want to instantiate an Array of a class that contains an Array (class Scene for exemple) it stops the program saying "Windows stoped fonctionning"... When I try to search for the error with break points I saw that it says "segmentation fault" when the program is at the destructor.
Here's my classes :
Array.h
#ifndef NAME_ARRAY_H
#define NAME_ARRAY_H
#include <stdexcept>
#include <iostream>
#include "malloc.h"
template <class T>
class Array {
private:
T *m_array;
unsigned int m_tot_size;
unsigned int m_actual_size;
public:
Array(unsigned int size);
Array(Array<T> const& paste);
bool add(T var);
const T& get(unsigned int index);
bool remove(unsigned int index);
void kill();
unsigned int getActualSize() const;
unsigned int getTotalSize() const;
T* getArray() const;
T& operator[](unsigned int index);
Array<T>& operator=(Array<T> const& paste);
~Array();
};
//CONSTRUCTOR
template <class T>
Array<T>::Array(unsigned int size) : m_tot_size(size), m_actual_size(0) {
m_array = (T*) malloc(size * sizeof(T));
}
template <class T>
Array<T>::Array(Array<T> const &paste) : m_tot_size(paste.m_tot_size),
m_actual_size(paste.m_actual_size) {
m_array = new T(*(paste.m_array));
}
//METHODES PUBLIC
template <class T>
const T & Array<T>::get(unsigned int index) {
if (index >= m_actual_size || index < 0)
throw std::out_of_range("Index out of range");
return m_array[index];
}
template <class T>
bool Array<T>::remove(unsigned int index) {
if(index < m_actual_size && m_actual_size != 0) {
m_actual_size--;
m_array[index] = m_array[m_actual_size];
return true;
}
return false;
}
template <class T>
bool Array<T>::add(T obj) {
if (m_actual_size >= m_tot_size) {
T *temp;
temp = (T*) realloc(m_array,5*sizeof(T));
m_array = temp;
m_array[m_actual_size] = obj;
m_actual_size++;
m_tot_size += 5;
return false;
} else {
m_array[m_actual_size] = obj;
m_actual_size++;
return true;
}
}
template <class T>
void Array<T>::kill() {
free(m_array);
delete [] m_array;
m_array = nullptr;
m_actual_size = 0;
m_tot_size = 0;
}
//ACCESSOR
template <class T>
unsigned int Array<T>::getActualSize() const { return m_actual_size; }
template <class T>
unsigned int Array<T>::getTotalSize() const { return m_tot_size; }
template <class T>
T* Array<T>::getArray() const { return m_array; }
//OPERATOR
template <class T>
T& Array<T>::operator[](unsigned int index) { return m_array[index]; }
template <class T>
Array<T>& Array<T>::operator=(Array<T> const& paste) {
if(this != &paste) {
m_tot_size = paste.m_tot_size;
m_actual_size = paste.m_actual_size;
free(m_array);
delete [] m_array;
m_array = nullptr;
m_array = new T(*(paste.m_array));
}
return *this;
}
//DESTRUCTOR
template <class T>
Array<T>::~Array() {
free(m_array);
delete [] m_array;
m_array = nullptr;
}
Scene.cpp :
#include "Scene.h"
Scene::Scene(std::string sceneName) : m_name(sceneName), m_array_position(20) {
}
void Scene::update() {}
void Scene::render() {}
Scene::~Scene() {
//m_array_position.kill();
//m_array_systems.kill();
}
Scene.h
#ifndef NAME_SCENE_H
#define NAME_SCENE_H
#include <string>
#include <unordered_map>
#include "../components/Position.h"
#include "../utils/Array.h"
#include "../systems/System.h"
class Scene {
private:
std::string m_name;
Array<Position> m_array_position;
public:
Scene(std::string sceneName);
void update();
void render();
~Scene();
};
main
Array<Scene> scenes(1);
I think the problem is that the program destroy the Array and then try to destroy the Array (Position is just a struct) but I'm not sure and I don't know what to do to correct it. Can someone please help me ?
I see in a lot of places code like this:
free(m_array);
delete [] m_array;
This doesn't look good to me. When allocating and deallocating memory, you have to match the allocation method with the deallocation:
If you reserve memory with "malloc", you free it with "free"
If you reserve with "new", you deallocate with "delete"
If you reserve with "new []", then you free with "delete []"
You should only use one of the methods or, if you REALLY need to mix them, then you should keep something tracking which method you would need to free the memory.
Related
Firstly, I have to print the value of Funcion "Ranking" which of parameter is Stack!
But my compiler says
I think that I delete memory which is not allocated. But, I can't find when I delete that memory....
Please help me the point I wrongly access memory.
P.S. I want to make a program that receive ints or strings and, put ints or strings into stack.
And use Ranking function as a Stack, the result would be,
For ints, how many numbers in stack which exceed first number of stack .
For strings, how many strings in stack which are later order than first string of stack.(The order of string objects is determined in the lexicographic order.)
For example, if inputs are 4 1 +2 5 3 -1 6 and the results is 2 (because 5 and 6 are bigger than first 4)
For example, if inputs are "to be or not to be" the results is 0 ( because there is no later order string than "to")
#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const size_t SIZE = 100;
using namespace std;
template <class T>
class Stack
{
public:
Stack(size_t size = SIZE);
Stack(const Stack<T>& s);
const Stack<T>& operator = (const Stack<T>& s); ~Stack();
bool isfull();
bool isEmpty();
void push(T d);
T pop();
T Elem(size_t i);
// int Ranking(T obj);
private:
T *_data;
size_t _top, _size;
};
template <class T>
Stack<T>::Stack(size_t size) : _top(0), _size(size)
{
_data = new T[size];
}
template <class T>
Stack<T>::Stack(const Stack<T>& s) : _top(s._top), _size(s._size)
{
if (_data) delete[] _data;
_size = s._size;
_top = s._top;
_data = new T[_size];
for (int i = 0; i < _size; ++i)
_data[i] = s._data[i];
}
template <class T>
Stack<T>::~Stack()
{
delete [] _data;
}
template <class T>
bool Stack<T>::isfull()
{
return _top == _size;
}
template <class T>
bool Stack<T>::isEmpty()
{
return _top == 0;
}
template <class T>
void Stack<T>::push(T d)
{
if (! isfull())
_data[_top++] = d;
}
template <class T>
T Stack<T>::pop()
{
if (! isEmpty())
return _data[--_top];
throw -1;
}
template <class T>
T Stack<T>::Elem(size_t i)
{
return _data[i];
}
template <class T>
int Ranking(T obj)
{
int k = 0;
while(!obj.isEmpty())
{
if(obj.Elem(0).compare(obj.pop()) < 0 )
k++;
}
return k;
}
int main(void)
{
int k = 0;
int value = 0;
int num;
string s;
string line;
Stack<string> strs;
Stack<string> temps;
vector<int> nums;
while (getline(cin, line))
{
istringstream ins(line);
while (ins >> s)
{
strs.push(s);
}
nums.push_back(Ranking(strs));
}
}
In the body of your copy constructor, _data is initially uninitialised. if (_data) has undefined behaviour, which you have observed as delete[]ing an arbitrary pointer value.
There is never a previous allocation in a new object, so you don't need to delete[] anything. You declare (in a non-traditional way) but don't define a copy assignment operator.
I've also implemented a move constructor, which can reduce the number of copies you need.
Most of the bodies of your constructors can go, or be moved to the member initialiser. It is better to use a pre-defined algorithm rather than do it yourself.
#include <algorithm>
#include <utility>
template <class T>
Stack<T>::Stack(size_t size) : _data(new T[size]), _top(0), _size(size)
{}
template <class T>
Stack<T>::Stack(const Stack<T>& s) : _data(new T[s._size]), _top(s._top), _size(s._size)
{
std::copy_n(s._data, s._size, _data);
}
template <class T>
Stack<T>::Stack(Stack<T>&& s) : _data(std::exchange(s._data, nullptr)), _top(s._top), _size(s._size)
{
}
template <class T>
Stack<T>& Stack<T>::operator=(Stack<T> s) // nb: by-value argument, copies or moves
{
std::swap(_data, s._data);
_size = s._size;
_top = s._top;
return *this;
}
I'm writing my own dynamic array class in C++ (similarly to std::vector), and I'm running into a problem when having a dynamic array containing dynamic arrays.
Basically when having an array of all data types (int, double, float, std::string etc.) there is no problem and all the functionalities of the class works great.
When the data type is another array though something messes up and there is an error raising in the end of the program (free(): double free detected in tcache 2)
All of the code:
DynamicArray.h:
#pragma once
#include <iostream>
namespace Utils
{
template <typename T>
class DynamicArray
{
private:
size_t array_length;
T* array;
public:
~DynamicArray();
DynamicArray();
DynamicArray(const int& initialLength);
void Print();
size_t GetLength() const;
void AddItem(const T& newItem);
// TODO: void AddItems(const T* newItemsArray);
void RemoveItem(int index);
T& GetItem(int index);
void SetItem(const int& index, const T& newValue);
T& operator [](int index) const;
void ResetArray(T resetValue);
};
}
#include "DynamicArray.cpp"
DynamicArray.cpp:
#include "DynamicArray.h"
template<typename T>
Utils::DynamicArray<T>::~DynamicArray()
{
std::cout << "before del" << this->array_length << "\n";
if (this->array_length > 0)
delete[] this->array;
std::cout << "after del\n";
}
template<typename T>
Utils::DynamicArray<T>::DynamicArray()
{
this->array_length = 0;
}
template<typename T>
Utils::DynamicArray<T>::DynamicArray(const int& initialLength)
{
this->array_length = initialLength;
T* new_array = new T[initialLength];
this->array = new_array;
}
template<typename T>
void Utils::DynamicArray<T>::Print()
{
for (size_t i = 0; i < this->array_length; i++)
std::cout << this->array[i] << std::endl;
}
template<typename T>
size_t Utils::DynamicArray<T>::GetLength() const
{
return this->array_length;
}
template<typename T>
void Utils::DynamicArray<T>::AddItem(const T& newItem)
{
T* new_array = new T[this->array_length + 1];
for (size_t i = 0; i < this->array_length; i++)
new_array[i] = this->array[i];
new_array[array_length] = newItem;
// Releasing the memory of array
if (this->array_length != 0)
{
delete[] this->array;
this->array = nullptr;
}
this->array_length += 1;
this->array = new_array;
}
template<typename T>
void Utils::DynamicArray<T>::RemoveItem(int index)
{
T* new_array = new T[this->array_length - 1];
int temp_index = 0;
for (size_t i = 0; i < this->array_length; i++)
{
if (i != index)
{
new_array[temp_index] = this->array[i];
temp_index++;
}
}
// Releasing the memory of array
delete[] this->array;
this->array = nullptr;
this->array_length -= 1;
this->array = new_array;
}
template <typename T>
T& Utils::DynamicArray<T>::GetItem(int index)
{
return this->array[index];
}
template<typename T>
T& Utils::DynamicArray<T>::operator[](int index) const
{
return this->array[index];
}
template <typename T>
void Utils::DynamicArray<T>::ResetArray(T resetValue)
{
for (int i = 0; i < this->array_length; i++)
this->array[i] = resetValue;
}
template <typename T>
void Utils::DynamicArray<T>::SetItem(const int& index,const T& newValue)
{
this->array[index] = newValue;
}
main function:
#include <iostream>
#include "DynamicArray.h"
int main()
{
Utils::DynamicArray<Utils::DynamicArray<double>> outputs;
Utils::DynamicArray<double> singleOutput;
singleOutput.AddItem(1);
singleOutput.AddItem(1);
outputs.AddItem(singleOutput);
}
Output given when running the program:
before del2
after del
before del1
before del2
free(): double free detected in tcache 2
Aborted (core dumped)
Any ideas? No matter what I tried nothing worked..
You failed to write proper copy constructor and assignment operators:
DynamicArray(DynamicArray const& rhs); // copy constructor
DynamicArray& operator=(DynamicArray const& rhs); // copy assignment
When you don't write these yourself, they are generated with shallow copy semantics. Since your class "owns" a pointer, if you shallow copy it, then two instances o DynamicArray both own the same pointner, and when one is destroyed, it destroys the data pointed to by the other. And when the other is destroyed, you get a double free.
To write these you need to allocate memory and do a full copy.
(You also would eventually want to write a move constructor, and move assignment operator.)
The element declared on the stack in main() is also copied into the other DynamicArray. The double free occurs when the stack of main is cleaned up: first delete is in the destructor of singleOutput, and the second delete is in the destructor of outputs, which holds an element that has the same pointer as singleOutput.
You also leave your "array" member uninitialized in the default constructor. That does not set it to zero, it leaves garbage in it. (Which could be zero, but might not be.)
I've been getting this error for some time, and I have no clue how to fix it.
I searched for similar problem here on stack overflow, but I've failed to find anything.
Source code:
template <typename T>
class Dynamic_Array
{
private:
T* actual_array;
unsigned int number_of_elements;
public:
Dynamic_Array() {}
~Dynamic_Array() {delete[] actual_array;}
unsigned int get_size() const {return number_of_elements;}
T& operator [](unsigned int index) {return actual_array[index];}
void operator +=(T&);
void operator -=(unsigned int);
};
template <typename T> /*Not sure if this is needed, but compiler doesn't mind, still prints the same error*/
void Dynamic_Array<T>::operator+=(T& object)
{
if(number_of_elements>1)
{
T* temp_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
temp_array[i]=actual_array[i];
}
delete[] actual_array;
actual_array = new T[number_of_elements+1];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array=NULL;
actual_array[number_of_elements]=object;
number_of_elements++;
}
else
{
number_of_elements++;
actual_array = new T[1];
}
}
void Dynamic_Array<T>::operator-=(unsigned int index)
{
T* temp_array = new T[number_of_elements-1];
for(unsigned int i=0, j=0;i<number_of_elements;i++)
{
if(i!=index)
{
temp_array[j]=actual_array[i];
j++;
}
}
delete[] actual_array;
number_of_elements--;
actual_array = new T[number_of_elements];
for(unsigned int i=0;i<number_of_elements;i++)
{
actual_array[i]=temp_array[i];
}
delete [] temp_array;
temp_array = NULL;
}
According to compiler, the error is present in line 18 (the empty one between "};" and "template"
As I said, I have no idea what I screwed up, so any help is appreciated.
When you define member functions outside of a class template declaration then you need to specify the template for each function. When you define
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
You need to have the template part as well like
template <typename T>
void Dynamic_Array<T>::operator-=(unsigned int index)
{
//...
}
This has to be present for every function definition that you do out of line. A single template <typename T> at the start of all the definition does not apply to all of the function definitions.
Dynamic_Array is a template class so when defining operator+= and operator-= outside the scope of the class you need to provide template type as follows:
template<typename T> void Dynamic_Array<T>::operator+=(T& object) {
//...
}
template<typename T> void Dynamic_Array<T>::operator-=(unsigned int index) {
//...
}
Also, I should note that it is somewhat odd to have void as a return type for operator+= and operator-=, typically you should return a reference to the altered instance of this, i.e:
template<typename T> Dynamic_Array<T>& Dynamic_Array<T>::operator+=(const T& object) {
//...
}
Hi I am having trouble implementing a simple pop function for a stack as an array program. The code is below and I am not sure how to fix it.
I am not sure about all the possible cases, so if you could just advise me then I would greatly appreciate!
#include "Exception.h"
template <typename Type>
class Drop_off_stack_as_array {
private:
int itop;
int ibottom;
int entry_count;
int array_capacity;
Type *array;
public:
Drop_off_stack_as_array( int = 10 );
Drop_off_stack_as_array( Drop_off_stack_as_array const & );
~Drop_off_stack_as_array();
int size() const;
bool empty() const;
Type top() const;
bool full() const;
void swap( Drop_off_stack_as_array & );
Drop_off_stack_as_array &operator = ( Drop_off_stack_as_array );
void push( Type const & );
Type pop();
void clear();
// Friends
template <typename T>
friend std::ostream &operator << ( std::ostream &, Drop_off_stack_as_array<T> const & );
};
template <typename Type>
Drop_off_stack_as_array<Type>::Drop_off_stack_as_array( int n ):
itop(0),
ibottom(0),
entry_count(0),
array_capacity(n),
array(new Type[array_capacity]){
//empty constructor
}
template <typename Type>
Drop_off_stack_as_array<Type>::Drop_off_stack_as_array( Drop_off_stack_as_array<Type> const &stack ):
itop( stack.itop ),
ibottom( stack.ibottom ),
entry_count( stack.entry_count ),
array_capacity( array_capacity ),
array( new Type[array_capacity] ) {
// The above initializations copy the values of the appropriate
// member variables and allocate memory for the data structure;
// however, you must still copy the stored objects.
for(int i = 0; i<array_capacity; i++){
array[i] = stack.array[i];
}
}
template <typename Type>
Drop_off_stack_as_array<Type>::~Drop_off_stack_as_array() {
delete[] array;
}
template <typename Type>
int Drop_off_stack_as_array<Type>::size() const {
return entry_count;
}
template <typename Type>
bool Drop_off_stack_as_array<Type>::full() const {
return (entry_count == array_capacity);
}
template <typename Type>
bool Drop_off_stack_as_array<Type>::empty() const {
return (entry_count == 0);
}
template <typename Type>
Type Drop_off_stack_as_array<Type>::top() const {
if(empty()){
throw underflow();
}
return array[itop];
}
template <typename Type>
void Drop_off_stack_as_array<Type>::swap( Drop_off_stack_as_array<Type> &stack ) {
std::swap( itop, stack.itop );
std::swap( ibottom, stack.ibottom );
std::swap( entry_count, stack.entry_count );
std::swap( array_capacity, stack.array_capacity );
std::swap( array, stack.array );
}
template <typename Type>
Drop_off_stack_as_array<Type> &Drop_off_stack_as_array<Type>::operator = ( Drop_off_stack_as_array<Type> rhs ) {
swap( rhs );
return *this;
}
template <typename Type>
void Drop_off_stack_as_array<Type>::push( Type const &obj ) {
if(full()){
array[ibottom] = 0;
itop = ibottom;
++ibottom;
}
else{
array[itop+1] = obj;
++itop;
++entry_count;
}
}
template <typename Type>
Type Drop_off_stack_as_array<Type>::pop() {
if(empty()){
throw underflow();
}
array[itop] = 0;
--itop;
--entry_count;
}
template <typename Type>
void Drop_off_stack_as_array<Type>::clear() {
delete [] array;
array = new Type(array_capacity);
}
Maybe something like this:
template <typename Type>
Type Drop_off_stack_as_array<Type>::pop() {
if(empty()){
throw underflow();
}
Type result = array[itop]; // Safe a copy of the top element
array[itop] = 0;
--itop;
--entry_count;
return result; // return it (your return type is not void,
// so you need a return statment which returns a value
}
What is strange in your code (and not just in this place) is the = 0 and what you are doing with the itop and ibottom counters/indices/...? But I guess that is another question waiting, your immediate problem is hopefully solved with the above.
(And next time at least include the error message/warning you get in the question, thanks!)
When you write template stack for class T, the class T can be an object and not primitive.
Also, you should not assume that class T has empty constructor, since it is enough for you copy constructor only.
Also, after element popped from stack, you have to release resources. In order to do so, you call destructor.
Please see the example implemented this:
code:
#include <new>
template<typename T>
class stack {
private:
int itop; // points to first free
int size; // maximal capacity
T * array; // memory for data
public:
stack(int n) : itop(0), size(n) {
array = (T *)(new char [sizeof(T) * n]);
}
~stack() {
delete [] (char *)array;
}
void push(const T &obj) {
if (itop < size) {
new (&array [ itop ++ ]) T(obj);
} else {
// error, stack is full
}
}
void pop() {
if (itop > 0) {
array[-- itop] . ~ T();
} else {
// error, stack is empty
}
}
const T &top () {
if (itop > 0) {
return array[( itop - 1)];
} else {
// error, stack is empty
}
}
};
I've been told to write header file to the main.cpp which contains this:
OOP::array tab;
for(int i = 0; i < rand()%10 + 1; ++i)
{
tab.push_back(new BaseClass("BaseClass 1"));
tab.push_back(new BaseClass("BaseClass 2"));
tab.push_back(new BaseClass("BaseClass 3"));
}
OOP::print_tab_el(tab); //prints tab using operator<< for its elements.
Class array is a container for smart pointers.
So I implemented counted_ptr, BaseClass and array (I used std::vector as a container) classes but when I invoke "print_tab_el(tab)" function, I get exclamation mark!
Seems like all of vector's items which are smart pointers contain "!" as name. I never put an "!" there.
Here's my header.
namespace OOP {
class BaseClass
{
public:
std::string name;
BaseClass(std::string arg) {name=arg;}
friend std::ostream & operator<<(std::ostream &os, const BaseClass& ref)
{
os<<ref.name<<"\n"; //gives ! ???
return os;
}
};
class array
{
public:
std::vector <counted_ptr<OOP::BaseClass> > myvec;
void push_back( OOP::BaseClass *arg)
{
counted_ptr< OOP::BaseClass> tmp(arg);
myvec.push_back(tmp);
}
};
void print_tab_el(array arr)
{
std::vector <counted_ptr<OOP::BaseClass> >::iterator it;
for (it=arr.myvec.begin();it!=arr.myvec.end();++it){
std::cout<<**it;
}
}
};
And this is program output:
!
!
!
!
!
!
!
!
and some more.
ADDED:
counted_ptr.cpp
#ifndef COUNTED_PTR_CPP
#define COUNTED_PTR_CPP
#include "counted_ptr.h"
#include <iostream>
/****************************************************************************/
template <class T>
counted_ptr<T>::counted_ptr(T* pointer):ptr(pointer)
{
refs.addRef();
}
/****************************************************************************/
template <class T>
counted_ptr<T>::counted_ptr(const counted_ptr& ref):ptr(ref.ptr), refs(ref.refs+1) {}
/****************************************************************************/
template <class T>
counted_ptr<T>::~counted_ptr()
{
if (refs.takeRef()==0)
delete ptr;
}
/****************************************************************************/
template <class T>
T* counted_ptr<T>::operator->(){
return ptr;
}
/****************************************************************************/
template <class T>
T& counted_ptr<T>::operator*(){
return *ptr;
}
/****************************************************************************/
template <class T>
counted_ptr<T>& counted_ptr<T>::operator=(const counted_ptr<T>& rcpt_r){
if (this!=&rcpt_r)
{
if (refs.takeRef()==0)
delete ptr;
ptr=rcpt_r.ptr;
//refs=rcpt_r.refs+1;
refs=rcpt_r.refs;
refs.addRef();
}
return *this;
}
/****************************************************************************/
#endif
counted_ptr.h
#ifndef COUNTED_PTR_H
#define COUNTED_PTR_H
#include "reference.h"
template <class T>
class counted_ptr{
public:
counted_ptr( T* pointer);
counted_ptr(const counted_ptr& ref);
~counted_ptr();
T* operator->();
T& operator*();
counted_ptr& operator=(const counted_ptr<T>& ref);
private:
T *ptr;
reference refs;
};
class testclass{};
#endif
#include "counted_ptr.cpp"
reference.cpp
#include "reference.h"
#include <iostream>
/****************************************************************************/
reference::reference():nr_of_references(0){}
/****************************************************************************/
reference::reference(const int value):nr_of_references(value){}
reference& reference::operator=(const int& ref)
{
nr_of_references=ref;
return *this;
}
/****************************************************************************/
reference::operator int()const
{
return nr_of_references;
}
/****************************************************************************/
int reference::addRef()
{
return ++nr_of_references;
}
/****************************************************************************/
int reference::takeRef()
{
return --nr_of_references;
}
/****************************************************************************/
reference.h
class reference{
public:
reference();
reference(const int value);
//reference& operator=(const reference& ref);
reference& operator=(const int& ref);
operator int()const;
int addRef();
int takeRef();
private:
int nr_of_references;
};
Every instance of counted_ptr has its own instance of reference. Each instance of reference has its own instance of nr_of_references. Although each counter_ptr manages reference properly, the problem is that the counted_ptr that only had a count of 1 will destruct the pointer when it goes out of scope, even after it was copied to a different counted_ptr instance.
Your counted_ptr needs to be redesigned so that all counted_ptrs to the same object also manipulate the same reference.