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
}
}
};
Related
struct PacketBase
{
virtual ~PacketBase() {}
template<class T>
const T& get() const
{
return static_cast<const PacketVal<T>&>(*this).val;
}
template<class T>
void set(const T& rhs)
{
return static_cast<PacketVal<T>>(*this).val = rhs;
}
};
template <typename T>
struct PacketVal : public PacketBase
{
T val;
PacketVal(const T& rhs) : val(rhs) {}
~PacketVal() {}
};
class CResponsePacket
{
private:
std::vector<std::pair<int, const PacketBase*>> m_vPacketData;
public:
void addValue(int n, const PacketBase& packetData)
{
m_vPacketData.emplace_back(std::make_pair(n, &packetData));
}
void print()
{
for ( auto& data : m_vPacketData )
{
std::printf("%d - ", data.first);
std::printf("%s\n", data.second->get<std::string>().c_str());
}
}
};
CResponsePacket has template class member-variable.
int main()
{
CResponsePacket packet;
std::string strAAA("AAA");
PacketVal<std::string> pVal(strAAA);
packet.addValue(1, pVal);
for ( int nIdx = 0; nIdx < 5; ++nIdx )
{
PacketVal<std::string> pp(strAAA);
packet.addValue(nIdx + 1, pp);
}
packet.print();
return 0;
}
The result is
1 - AAA
1 -
2 -
3 -
4 -
5 -
Because the instance is in a loop, memory is destroyed. But this is just an example, and I have to use loop actually. How can I solve this...?
......................
..................
You can make use of std::shared_pointer or std::unique_ptr (depending of your use), and so having the vector looking like this:
std::vector<std::pair<int, std::shared_pointer<PacketBase>>> m_vPacketData;
And so then the addValue method should look like this:
void addValue(int n, const PacketBase& packetData)
{
m_vPacketData.emplace_back(
std::make_pair(
n,
std::make_shared<PacketBase>(packetData)
)
);
}
This will make a copy of packetData on the heap, and store the reference in a shared pointer. If you don't what this copy to be made, then you have to define a new constructor in PacketBase
class PacketBase{
public:
PacketBase(PacketBase&& el): attr(std::move(el.attr))... {...}
}
and then redefining the addValue that accept a rvalue reference
void addValue(int n, PacketBase&& packetData)
{
m_vPacketData.emplace_back(
std::make_pair(
n,
std::make_shared<PacketBase>(std::move(packetData))
)
);
}
And then actually calling the right addValue from main:
for ( int nIdx = 0; nIdx < 5; ++nIdx )
{
PacketVal<std::string> pp(strAAA);
packet.addValue(nIdx + 1, std::move(pp));
}
Or actually just:
for ( int nIdx = 0; nIdx < 5; ++nIdx )
packet.addValue(nIdx + 1, PacketVal<std::string>(strAAA););
This will obviously force you to rewrite the entire class, because you are changing the attribute type... the other way that you can achieve this is switch from
m_vPacketData.emplace_back(std::make_pair(n, &packetData));
to
m_vPacketData.emplace_back(std::make_pair(n, new PacketVal(packetData)));
But you have then remember to delete the objects on the heap or you will have memory leaks
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.
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) {
//...
}
There are some Classes: Array, NumericArray. Array is a template class, and NumericArray is a class inherited from Array designed to take int, double, etc.
Part of Header of NumericArray:
template <class T = int>
class NumericArray : public Array<T>{
private:
T* m_data;
int size;
public:
NumericArray<T> operator * (T factor)const;
};
here are constructors and some functions of NumericArray:
template <class T>
NumericArray<T>::NumericArray(){
m_data = new T[10];
size = 10;
}
template <class T>
NumericArray<T>::NumericArray(int n){
m_data = new T[n];
size = n;
}
template <class T>
NumericArray<T>::NumericArray(const NumericArray<T>& s_data){
m_data = new T[s_data.size];
// assign elements in the source array
for (int i = 0;i<=(s_data.Size()-1 ); i++){
m_data[i] = s_data.m_data[i];
}
size = s_data.Size();
}
/* Destructor */
template <class T>
NumericArray<T>::~NumericArray(){
delete [] m_data;
}
template <class T>
NumericArray<T> NumericArray<T>::operator * (T factor)const{
NumericArray<T> temp(size);
for (int i = 0; i<size;i++){
temp.m_data[i] = (*this)[i] *factor;
}
return temp;
}
And when I call it in the main(), something weird happens. For example:
NumericArray<int> intArray1(10);
NumericArray<int> intArray2;
for(int i =0; i<10;i++){
intArray1[i] = i;
intArray2[i] = i;
}
The 2 arrays do contain numbers 0-9, but if I call
NumericArray intArray4 = intArray1*2;
intArray4 consists of zero(0)s. It seems that the default constructor is called in the function and passed to Array4. And after the operator, Array1 and Array2 are still numbers 0-9
Below are the related code of Array
template class Array{
private:
T* m_data;
int size;
public:
Array(); // constructor
Array(int n); // constructor
Array(const Array<T>& s_data); //Copy Constructor
virtual ~Array(); // destructor
void SetElement(int i, const T& source);
T& GetElement(int i)const;
int Size() const;
int DefaultSize()const;
void DefaultSize(int n);
// Operator overloading
Array<T>& operator = (const Array<T>& source) ;
T& operator [](int i);
const T& operator [] (int i) const;
};
template <class T>
Array<T>::Array(){
// default constructor
m_data = new T[defaultSize]; // initialize T*
size = defaultSize; // initialize integer
}
template <class T>
Array<T>::Array(int n){
// Constructor with arguments
m_data = new T[n];
size = n;
}
template <class T>
Array<T>::Array(const Array<T>& s_data){
// Copy constructor
m_data = new T[s_data.Size()];
// assign elements in the source array
for (int i = 0;i<=(s_data.Size()-1 ); i++){
m_data[i] = T( s_data.m_data[i]);
}
size = s_data.Size();
defaultSize = s_data.Size();
}
template <class T>
T& Array<T>::operator [](int i) {
if (i > size|| i<0){
OutOfBoundsException a;
throw a;
}
return m_data[i];
}
Not sure if provided enough information. Any hint is greatly appreciated.
The easiest way to access base class data members when the base is a (dependent) class template, is a using declaration like this:
#include <iostream>
using namespace std;
template< class Item >
class Base
{
protected:
Item item_;
Base( Item const& v ): item_( v ) {}
};
template< class Item >
class Derived
: public Base< Item >
{
protected:
using Base<Item>::item_;
public:
auto value() const -> Item { return item_; }
Derived( Item const& v ): Base<Item>( v ) {}
};
auto main() -> int
{
Derived<int> const x( 42 );
cout << x.value() << endl;
}
Alternatively you can qualify the access, e.g. this->item_ or Base<Item>::item_.
That said, it’s usually not a good idea to let derived classes access base class data members directly.
Here is the problem: both NumericArray and Array have
T* m_data;
int size;
The function Array::operator[] is called from Array which uses Array::m_data, however the NumericArray::operator* sets NumericAray::m_data. It probably is working as you would expect, but you are reading from the wrong pointer.
Remove the members from NumericArray and make the members protected instead of private in Array. The second part is optional if the implementation is changed a little bit.
Not 100% sure whether my question is worded correctly as I don't fully understand my problem.
For my course I need to create my own smart pointer to clean up after itself.
Here's my code so far:
Header:
class Test
{
public:
Test()
{
m_iTest1 = 4;
m_iTest2 = 3;
m_iTest3 = 2;
m_iTest4 = 1;
}
Test (int a, int b, int c, int d)
{
m_iTest1 = a;
m_iTest2 = b;
m_iTest3 = c;
m_iTest4 = d;
}
Test(const Test& a_oTest)
{
m_iTest1 = a_oTest.m_iTest1;
m_iTest2 = a_oTest.m_iTest2;
m_iTest3 = a_oTest.m_iTest3;
m_iTest4 = a_oTest.m_iTest4;
}
~Test(){;}
int m_iTest1;
int m_iTest2;
int m_iTest3;
int m_iTest4;
};
template<class T>
class SmartData
{
public:
template<class T> friend class SmartPointer;
SmartData();
SmartData(const T& a_oData);
~SmartData();
T operator * () const;
unsigned int GetCount(){return m_uiCount;}
protected:
void IncrementCount(){++m_uiCount;}
void DecrementCount();
void DeleteThis();
unsigned int m_uiCount;
T* m_poData;
};
template<class T>
class SmartPointer
{
public:
SmartPointer();
SmartPointer(SmartData<T>& a_oSmartData);
SmartPointer(const SmartPointer& a_oSmartPointer);
~SmartPointer();
SmartPointer<T>& operator = (const SmartPointer<T>& a_oSmartPointer);
T operator *() const;
SmartData<T>* operator ->() const;
unsigned int GetCount() const;
private:
SmartData<T>* m_poSmartData;
};
#include "smartpointer.inl"
Inline file:
template<class T>
SmartData<T>::SmartData()
{
m_uiCount = 0;
m_poData = new T();
}
template<class T>
SmartData<T>::SmartData(const T& a_oData)
{
m_uiCount = 0;
m_poData = new T(a_oData);
}
template<class T>
SmartData<T>::~SmartData()
{
if (m_poData)
{
delete m_poData;
}
}
template<class T>
T SmartData<T>::operator * () const
{
return *m_poData;
}
template<class T>
void SmartData<T>::DecrementCount()
{
if (m_uiCount - 1 == 0 || m_uiCount == 0)
{
DeleteThis();
return;
}
--m_uiCount;
}
template<class T>
void SmartData<T>::DeleteThis()
{
if (m_poData)
{
delete m_poData;
m_poData = 0;
}
}
template<class T>
SmartPointer<T>::SmartPointer()
{
m_poSmartData = new SmartData<T>();
m_poSmartData->IncrementCount();
}
template<class T>
SmartPointer<T>::SmartPointer(SmartData<T>& a_oSmartData)
{
m_poSmartData = &a_oSmartData;
m_poSmartData->IncrementCount();
}
template<class T>
SmartPointer<T>::SmartPointer(const SmartPointer& a_oSmartPointer)
{
m_poSmartData = a_oSmartPointer.a_oSmartData;
m_poSmartData->IncrementCount();
}
template<class T>
SmartPointer<T>::~SmartPointer()
{
m_poSmartData->DecrementCount();
m_poSmartData = 0;
}
template<class T>
SmartPointer<T>& SmartPointer<T>::operator = (const SmartPointer<T>& a_oSmartPointer)
{
m_poSmartData = a_oSmartPointer.m_poSmartData;
m_poSmartData->IncrementCount();
}
template<class T>
T SmartPointer<T>::operator *() const
{
return *m_poSmartData->m_poData;
}
template<class T>
SmartData<T>* SmartPointer<T>::operator ->() const
{
return m_poSmartData;
}
template<class T>
unsigned int SmartPointer<T>::GetCount() const
{
return m_poSmartData->m_uiCount;
}
main.cpp
void SomeFunction1(SmartData<Test>& a_SmartData)
{
SmartPointer<Test> oSmartPointer2(a_SmartData);
}
void main()
{
SmartData<int> oSmartData1(5);
if (1)
{
SmartPointer<int> oSmartPointer1(oSmartData1);
int iTemp1 = oSmartPointer1->GetCount();
int iTemp2 = *oSmartPointer1;
int iTemp3 = *oSmartData1;
}
if (1)
{
SmartData<int> oSmartData2(5);
}
SmartData<Test> oSmartData3;
(*oSmartData3).m_iTest1 = 5; //Does not work
if (1)
{
SmartData<Test> oSmartData4(oSmartData3);
SomeFunction1(oSmartData3);
//oSmartData4 still exits
}
}
Everything works fine, the data is cleaned up after itself and I get no leaks... except for one line:
(*oSmartData3).m_iTest1 = 5;
I'm compiling with visual studio, and when I place the "." after "(*oSmartData3)"... "m_iTest1" comes up correctly. Except I get an error:
error C2106: '=' : left operand must be l-value
I'm not sure why this doesn't work or what to change so it does work.
Look closer at the declaration of operator*() in SmartData:
T operator * () const;
This means that this operator is returning an object of type T, which is a copy of m_poSmartData->m_poData. It is a temporary object in this context:
(*oSmartData3).m_iTest1 = 5; //Does not work
Of course, you cannot assign a value to a temporary object, because it is not an l-value. Read more about what l-values and r-values are here: http://publib.boulder.ibm.com/infocenter/comphelp/v7v91/index.jsp?topic=%2Fcom.ibm.vacpp7a.doc%2Flanguage%2Fref%2Fclrc05lvalue.htm
I would suggest that you return a reference to m_poSmartData->m_poData
in operator*() (if I'm understanding correctly what you are trying to do).
Your T operator *() const is returning a temporary object (i.e. a copy), which is not an l-value (cannot be assigned to). Return a reference instead:
T& operator *() const;
Does this work:
oSmartData3.m_iTest1 = 5;