C++ own Stack of objects. What is copied at push()? - c++

Well, i implemented a FIFO stack (push,pop) stack in a Class with mem allocated ints.
So i asked to myself: if "int" is a datatype, why i cannot push "ADTs" to my own stack.
Then i came with this code:
#include <iostream>
class Person {
std::string name;
int age;
public:
Person(std::string pName = "", int pAge = 1)
{
name = pName;
age = pAge;
}
void Print()
{
std::cout << name << " " << age << std::endl;
}
};
class Stack {
Person * stack;
int size, top;
int index;
public:
Stack(int stackSize)
{
top = stackSize -1;
index = top;
stack = new Person[stackSize];
}
void push(Person person)
{
if (index < 0)
std::cout << "Stack UNDERFLOW" << "Index is: " << index << std::endl;
stack[index--] = person;
}
Person & pop()
{
if (index > top)
{
std::cout << "Stack OVERFLOW" << std::endl;
}
return stack[++index];
}
};
I know, there are stacks, queues, vectos, etc in the STL lib. I just wanted to do it by myself.
I want the stack push a copy of the object.
I'm not sure i don't know if the compiler is pushing addresses, copying the whole object (what is what i want) or what.
Please enlight me.
Here is my main() code:
int main()
{
Stack stack(100);
Person person("Lucas", 39);
for (int i = 0; i < 100; i++)
{
stack.push(person);
((Person)stack.pop()).Print();
}
return EXIT_SUCCESS;
}

To answer your question about copies, this:
stack[index--] = person;
makes a copy, because the type on both sides of the assignment is of type T.
This:
stack.push(person);
also makes a copy, because you are passing person by value. To avoid this (redundant) copy, declare push as:
void push(const T &person)

Well, what i did to solve my question was what #PaulMcKenzie said in his comment.
I created a template for the "Stack" class and any template "T" is the datatype that is passed to the this class.
About the main methond (in my question) it had an unnecesary cast to (Person) since it's implied.
Edit 2:
#Paul Sanders were right too, i was doing a redundant copy at push()
This way i solved my problem:
#include <iostream>
class Person {
std::string name;
int age;
public:
Person(std::string pName = "", int pAge = 1)
{
name = pName;
age = pAge;
}
void Print()
{
std::cout << name << " " << age << std::endl;
}
};
template <class T>
class Stack {
T * stack;
int size, top;
int index;
public:
Stack(int stackSize)
{
top = stackSize -1;
index = top;
stack = new T[stackSize];
}
void push(const T &person)
{
if (index < 0)
std::cout << "Stack UNDERFLOW" << std::endl;
stack[index--] = person;
}
T pop()
{
if (index > top)
{
std::cout << "Stack OVERFLOW" << std::endl;
}
return stack[++index];
}
};
int main()
{
Stack<Person> stack(100);
Person person1("Lucas", 39);
Person person2("Gustavo", 38);
for (int i = 0; i < 100; i++)
{
if (i % 2 == 0)
stack.push(person1);
else
stack.push(person2);
}
for (int i = 0; i < 100; i++)
stack.pop().Print();
return EXIT_SUCCESS;
}
In the example of the main() function, it creates an stack of Person objects of 100. Then i create 2 people: "Lucas" and "Gustavo" and push it intercalated to the my stack for 100 times (the first for statment).
Then the second and final for statement pop() all values and print them.

Related

'<' unable to resolve function overload and Parameters mismatch in Class template, Visual Studio compiler

The error pointed out was at the end just before the };
I don't even see any function overloading or any mismatching parameters.
This is simply a queue data structure that I was trying to implement. But unfortunately, I got these compiler errors. I am sharing the whole code so that easily one can help, since neither I have any function overloaded, not even the constructor nor I have used mismatched parameter. I guess image will help out to see the error.
template<class T>
class Queue {
private:
T* box;
int front;
int rear;
int number_Of_Elements;
int capacity;
public:
Queue(int cap = 0) {
capacity = cap;
front = rear = 0;
number_Of_Elements = 0;
}
bool Empty() {
return size == 0;
}
int next(int i) {
return ((i + 1) % capacity);
}
int previous(int i) {
return ((i + (capacity - 1)) % capacity);
}
int get_Number_Of_Elements() {
return number_Of_Elements;
}
void double_Box() {
T* temp = new T[capacity * 2];
for (int i = 0; i < size; i++) {
temp[i] = box[i];
}
front = 0;
rear = number_Of_Elements;
delete[] box;
box = temp;
}
const T& peek() {
T a = box[front];
front = next(front);
return a;
}
void printQueue() {
cout << "Front is at : " << front << endl;
cout << "Rear is at : " << rear << endl;
for (int i = 0; i < number_Of_Elements; i++) {
cout << "box[" << i << "]" << " : " << box[i] << endl;
}
cout << "------------------------" << endl;
}
void Enqueue(const T& data);
const T& Dequeue();
~Queue() {
delete[] box;
}
// error is exactly here -> };
};
Your problem is with size. You haven't declared it.
I think the compiler tries to use some global function called size instead but it fails.
After declaring the capacity member var, add
size_t size;
Demo
The answer is, there were issues, like some of the variables were not even initialized but they were being used, and the memory calculation errors were there. Like a pointer pointing somewhere in memory that actually does not exist.

Dynamic object array not working

I have one parent and two children, I want to create a dynamic array that contains the children (not allowed to use vectors). I created the classes and everything, and I get no compilation errors or warnings, but when I try to access a member of the array and print its content, nothing happens.
I'm aware there may be some bad coding style here, but I'm only interested in knowing why the array isn't working. I think it's because I created an array of objects, instead of an array of pointers to objects, I'm not sure.
(I removed the 2nd child from the code because it's irrelevant here)
#pragma warning(disable:4996)
using namespace std;
#include <iostream>
#include <cstdlib>
#include <cctype>
#include "date.h"
#define ADDRESS_SIZE 512
#define NAME_SIZE 128
#define DATE_SIZE 128
class Treatment {
protected:
int treatment_ID;
int patient_ID;
Date treatment_date;
int treatment_costs;
public:
Treatment() {}
Treatment(int treatment_ID, int patient_ID, int treatment_costs, char treatment_date[DATE_SIZE]) {
this->treatment_ID = treatment_ID;
this->patient_ID = patient_ID;
this->treatment_costs = treatment_costs;
this->treatment_date.convert_date(treatment_date);
}
void set_treatment_ID(int treatment_ID) {
this->treatment_ID = treatment_ID;
}
void read_treatment_date(void) {
treatment_date.read_date();
}
void set_treatment_date(char _date[DATE_SIZE]) {
treatment_date.convert_date(_date);
}
void set_patient_ID(int patient_ID) {
this->patient_ID = patient_ID;
}
void set_treatment_costs(int treatment_costs) {
this->treatment_costs = treatment_costs;
}
int get_treatment_ID(void) {
return treatment_ID;
}
int get_patient_ID(void) {
return patient_ID;
}
int get_treatment_costs(void) {
return treatment_costs;
}
};
class Outside_treatment : public Treatment {
private:
int clinic_num;
//class doctor;
public:
Outside_treatment() {}
Outside_treatment(int clinic_num, int treatment_ID, int patient_ID, int treatment_costs, char treatment_date[DATE_SIZE]) :Treatment(treatment_ID, patient_ID, treatment_costs, treatment_date) {
this->clinic_num = clinic_num;
}
void set_clinic_num(int clinic_num) {
this->clinic_num = clinic_num;
}
int get_clinic_num() {
return this->clinic_num;
}
void print_outside_treatment(void) {
cout << "The clinic num is " << clinic_num << "\n";
cout << "The treatment ID is " << treatment_ID << "\n";
cout << "The patient_ID is " << patient_ID << "\n";
cout << "The treatment costs are " << treatment_costs << "\n";
treatment_date.print_date();
cout << " treatment date in compare format is " << treatment_date.get_compare();
}
};
class Dynarray {
private:
Treatment *pa;
int length;
int nextIndex;
public:
Dynarray() {
pa = new Treatment[10];
length = 10;
nextIndex = 0;
}
~Dynarray() {
delete[]pa;
}
void add(Treatment &add) {
Treatment *pnewa;
if (nextIndex == length) {
length += 10;
pnewa = new Treatment[length];
for (int i = 0; i < nextIndex; ++i) {
pnewa[i] = pa[i];
}
delete[]pa;
pa = pnewa;
}
pa[nextIndex++] = add;
}
Treatment &operator[](int index) {
return *(pa + index);
}
};
int main(void) {
Outside_treatment it;
cout << "Enter the patient ID\n";
int p_id;
cin >> p_id;
it.set_patient_ID(p_id);
cin.ignore();
cout << "set treatment date\n";
it.read_treatment_date();
cout << "enter costs\n";
int costs;
cin >> costs;
it.set_treatment_costs(costs);
cout << "enter section num\n";
int sc_num;
cin >> sc_num;
it.set_clinic_num(sc_num);
it.print_outside_treatment();
Dynarray da;
da.add(it);
Treatment *yetanotherpointer = &da[0];
int i = yetanotherpointer->get_patient_ID();
cout << i << endl;
while (1);
};
You are creating an array of Treatment object instances. As such, you cannot store any derived types at all. If you try to assign an object of a derived type to a Treatmentobject, it will get sliced.
Your hunch is correct. Since you are dealing with polymorphic types, you need to store pointers to objects, not actual objects, in the array. Then you can store Treatment* pointers to objects of any derived type, eg:
class Treatment {
...
public:
...
// make the base class destructor virtual so calling
// 'delete' on a base class pointer will invoke derived
// destructors. Otherwise, if a derived class has any
// data members with a non-trivial destructor, you will
// cause leaking. When writing polymorphic classes, it
// is common practice to always define a virtual destructor,
// just in case...
//
virtual ~Treatment() {} // <-- add this
..
};
class Dynarray {
private:
Treatment **pa;
int length;
int capacity;
// prevent copying the array, otherwise you risk
// memory errors if multiple arrays own the same
// objects being pointed at and try to free them
// multiple times. Copying pointers to owned objects
// is not safe, you need a cloning mechanism to
// make deep-copies of derived types so a copied
// array can point to its own objects...
Dynarray(const Dynarray &) {}
Dynarray& operator=(const Dynarray &) {}
public:
Dynarray(int initialCapacity = 10) {
pa = new Treatment*[initialCapacity];
capacity = initialCapacity;
length = 0;
}
~Dynarray() {
for (int i = 0; i < length; ++i)
delete pa[i];
delete[] pa;
}
void add(Treatment *add) {
if (length == capacity) {
Dynarray temp(capacity + 10);
for (int i = 0; i < length; ++i) {
temp.pa[i] = pa[i];
}
Treatment *ptr = temp.pa;
temp.pa = pa;
pa = ptr;
capacity = temp.capacity;
}
pa[length++] = add;
}
Treatment* operator[](int index) {
return pa[index];
}
};
int main(void) {
Outside_treatment *ot = new Outside_treatment;
cout << "Enter the patient ID\n";
int p_id;
cin >> p_id;
ot->set_patient_ID(p_id);
cin.ignore();
cout << "set treatment date\n";
ot->read_treatment_date();
cout << "enter costs\n";
int costs;
cin >> costs;
ot->set_treatment_costs(costs);
cout << "enter section num\n";
int sc_num;
cin >> sc_num;
ot->set_clinic_num(sc_num);
ot->print_outside_treatment();
Dynarray da;
da.add(ot);
Treatment *t = da[0];
int i = t->get_patient_ID();
cout << i << endl;
while (1);
};
On the other hand, if the array doesn't need to own the objects being pointed at, just store the pointers, you can remove the delete loop in the destructor, and the caller is not required to use new to create objects being stored, and making a copy of the array is safe, eg:
class Dynarray {
private:
Treatment **pa;
int length;
int capacity;
public:
Dynarray(int initialCapacity = 10) {
pa = new Treatment*[initialCapacity];
capacity = initialCapacity;
length = 0;
}
// coping is OK since the objects being pointed
// at are not owned by the array!
Dynarray(const Dynarray &src) {
pa = new Treatment*[src.capacity];
capacity = src.capacity;
length = src.length;
for (int i = 0; i < length; ++i) {
pa[i] = src.pa[i];
}
}
Dynarray& operator=(const Dynarray &rhs) {
if (&rhs != this) {
Dynarray temp(rhs);
Treatment **ptr = temp.pa;
temp.pa = pa;
pa = ptr;
capacity = rhs.capacity;
length = rhs.length;
}
return *this;
}
~Dynarray() {
delete[] pa;
}
void add(Treatment *add) {
if (length == capacity) {
Dynarray temp(capacity + 10);
for (int i = 0; i < length; ++i) {
temp.pa[i] = pa[i];
}
Treatment **ptr = temp.pa;
temp.pa = pa;
pa = ptr;
capacity = temp.capacity;
}
pa[length++] = add;
}
Treatment* operator[](int index) {
return pa[index];
}
};
int main(void) {
Outside_treatment ot;
cout << "Enter the patient ID\n";
int p_id;
cin >> p_id;
ot.set_patient_ID(p_id);
cin.ignore();
cout << "set treatment date\n";
ot.read_treatment_date();
cout << "enter costs\n";
int costs;
cin >> costs;
ot.set_treatment_costs(costs);
cout << "enter section num\n";
int sc_num;
cin >> sc_num;
ot.set_clinic_num(sc_num);
ot.print_outside_treatment();
Dynarray da;
da.add(&ot);
Treatment *t = da[0];
int i = t->get_patient_ID();
cout << i << endl;
while (1);
};

Why is the 98th element in my Stack implementation such a bizarre value?

I have the following stack data structure implementation in C++:
// file: Stack.h
#pragma once
#include <iostream>
#include <exception>
class CStack
{
private:
int counter;
int *data;
int currentmaxsize;
void adjust();
public:
void push(int value);
int pop();
int peek();
int getsize();
CStack();
~CStack();
};
// file: Stack.cpp
#include "Stack.h"
void CStack::adjust()
{
int *temp = new int[currentmaxsize];
for (int i = 0; i < counter; i++)
{
temp[i] = data[i];
}
delete data;
data = new int[currentmaxsize * 2];
for (int i = 0; i < counter; i++)
{
data[i] = temp[i];
}
delete temp;
currentmaxsize *= 2;
}
int CStack::getsize()
{
return counter;
}
void CStack::push(int value)
{
if (counter+1 == currentmaxsize)
{
adjust();
}
counter++;
data[counter] = value;
}
int CStack::peek()
{
return data[counter];
}
int CStack::pop()
{
if (counter > 0)
{
int ret = data[counter];
counter--;
return ret;
}
else if (counter == 0)
{
throw std::exception("cannot pop empty stack");
}
return 0xFFFFFFFF;
}
CStack::CStack()
{
data = new int[100];
currentmaxsize = 100;
counter = 0;
}
CStack::~CStack()
{
delete data;
}
This is a fairly standard stack implementation. The only thing that is different from the kind of stack you would see in most textbooks is the adjust() function, which reallocates the stack with a bigger size if the original boundary is reached.
I wrote the following driver for the data structure as well:
// file: driver.cpp
#include <iostream>
#include "Stack.h"
int main(int argc, char *argv[])
{
CStack stack;
for (int i = 0; i < 200; i++)
{
stack.push(i);
std::cout << "Pushed: " << i << std::endl;
//std::cout << "New stack size: " << stack.getsize() << std::endl;
}
int len = stack.getsize();
std::cout << "len = " << len << std::endl;
for (int i = 0; i < len; i++)
{
std::cout << "Popped: " << stack.pop() << std::endl;
//std::cout << "New stack size: " << stack.getsize() << std::endl;
}
return 0;
}
This works almost as I would expect it to, except this one value in the program output:
Popped: 100
Popped: 99
Popped: 7798895
Popped: 97
Popped: 96
It is always the value of the 98th element in the stack that has a bizarre value like this, and I don't know why it is - the adjust() function is being called when the stack hits 100 values, not 99, so I don't imagine it's a problem with the adjust function.
Your push and peek and probably other functions use counter as the index of the last element. But other parts of your code use counter as the number of elements so counter-1 would be the index of last. So data is lost during adjust
Select one design: The valid indexes are 0 through counter-1 inclusive or 0 though counter or 1 through counter (wasting position 0).
I only like the first of those choices but any one of them can work (your existing code is closest to being the third). Having different parts play by different rules doesn't work.
I see at least one bug. You are using delete after doing a new[].
new should be matched with delete and new[] should be matched with delete[]. Otherwise it's undefined behavior.
Also, you are doing unnecessary copying in your adjust function.

Can't assign in an array of pointers

My problem is in adaugare function on this line I think persoane[numar_persoane] = pers. Because that line gives me this error. What problem do I have?
I have to use a dynamic array of pointers.
class baze
{
private: int numar_persoane=0;
persoana (*persoane)=(persoana *)malloc(0);
public: baze()
{
persoane = NULL;
}
~baze()
{
delete[] persoane; //???????????
}
void adaugare(persoana pers)
{
numar_persoane++;
realloc(persoane, sizeof(persoana)*numar_persoane);
persoane[numar_persoane] = pers;
};
void afisarealfa()
{
for (int i = 0; i < numar_persoane; i++)
for (int j = i + 1; j < numar_persoane; j++)
if (persoane[i].gnume()>persoane[i].gnume())
{
persoana aux;
aux = persoane[i];
persoane[i] = persoane[j];
persoane[j] = aux;
}
for (int i = 0; i < numar_persoane; i++)
{
cout << "Nume:" << persoane[i].gnume() << endl;
cout << "Varsta" << persoane[i].gan() << endl;
cout << "sex" << persoane[i].gsex();
}
}
This is persoana class:
class persoana
{
private: string nume;
int an;
char sex;
public: void snume(string numebagat)
{
nume = numebagat;
}
string gnume()
{
return nume;
}
void san(int anbagat)
{
an = anbagat;
}
int gan()
{
return an;
}
void ssex(char sexbagat)
{
sex = sexbagat;
}
char gsex()
{
return sex;
}
};
Main:
int _tmain(int argc, _TCHAR* argv[])
{
persoana a;
a.san(1990);
a.snume("Gogu");
a.ssex('m');
cout << "Nume: " << a.gnume() << endl << "Anul nasterii: " << a.gan() << endl << "Sex: " << a.gsex();
baze b;
b.adaugare(a);
return 0;
}
As #simpletron pointed out, malloc(0) is kind of weird. I wasn't even sure it was legal, but per what's the point in malloc(0)?, it is legal albeit implementation defined (it might be NULL, it might be a valid empty region; either way, you can call free on it, and per Is a malloc() needed before a realloc()? you can just skip that malloc;
Using malloc but then delete is not recommended; per Behaviour of malloc with delete in C++, this IS undefined behavior; you should probably be using free to go with realloc instead of delete
You have an off by one error. You should use persoane[numar_persoane-1] = pers;
You probably should set age/sex to some default value in the constructor.
This might be my personal preference, but I dislike copying classes around versus pointer to classes.

Reverse a string by using unique pointer c++

Below are my .cpp file and .h file. After getting a lot of help from Mike, I finally get it working; however, when I compile it on Visual Studio 2012, it gives me 2 warnings about '<' signed/unsigned mismatch right on the line "for (int i = 0; i < s.length(); i++)". Can anyone tell me what I did wrong in there ?
[code]
#include"DownwardStack.h"
#include<iostream>
#include<string>
#include<memory>
#include<cassert>
using namespace std;
unique_ptr<string> reverse_string(string const &s);
int main()
{
int count = 0;
string s;
unique_ptr<string> reverse(new string());
unique_ptr<DownwardStack<int>> ptr(new DownwardStack<int>());
cout << "Your string: ";
cin >> s;
reverse = reverse_string(s);
cout << "Your reverse string is: " << *reverse << endl;
if(ptr->IsEmpty())
cout << "ptr is empty" << endl;
else
cout << "ptr is not empty" << endl;
assert(ptr->IsEmpty());
assert(!ptr->IsFull());
ptr->Push(5);
ptr->Push(7);
ptr->Push(10);
ptr->Push(15);
ptr->Push(4);
cout << "Stack size: " << ptr->GetSize() << endl;
cout << "Top element: " << ptr->Peek() << endl;
cout << "Pop one element out." << endl;
ptr->Pop();
cout << "Top element: " << ptr->Peek() << endl;
return 0;
}
unique_ptr<string> reverse_string(string const &s)
{
DownwardStack<char> stack;
cout << s.length() << endl;
// Here it gives me a warning on the for loop
for (int i = 0; i < s.length(); i++)
{
stack.Push(s[i]);
}
unique_ptr<string> result(new string);
// Again it gives me a warning on the for loop
for(int i = 0; i < s.length(); i++)
{
*result += stack.Peek();
stack.Pop();
}
return result;
}
[/code]
This is my header file .h
[code]
#pragma once
#include<cassert>
#include<stack>
#include<string>
// size: number of elements inside the array
const int FIXED_ARRAYED_STACK_CAPACITY = 100;
template<class T>
class DownwardStack
{
public:
DownwardStack();
~DownwardStack();
// 1 step
// O(0)
int GetSize() const {return size;}
bool IsEmpty() const {return (size==0);}
bool IsFull() const {return (size==FIXED_ARRAYED_STACK_CAPACITY);}
T Peek();
void Pop();
void Push(T val);
void Clear();
void DisplayStack();
private:
int size;
T elements[FIXED_ARRAYED_STACK_CAPACITY];
};
// O(1)
template<class T>
DownwardStack<T>::DownwardStack()
{
size = 0;
}
template<class T>
DownwardStack<T>::~DownwardStack()
{
}
// assert = 1 step
// IsEmpty() = 1 step
// total = 2 steps
// f(n) = 2
// O(1)
template<class T>
T DownwardStack<T>::Peek()
{
assert(!IsEmpty());
return elements[FIXED_ARRAYED_STACK_CAPACITY - size];
}
// In order to take something out, it must not be empty
// assert = 1 step
// IsEmpty() = 1 step
// size-- = 1 step
// total = 3 steps
// O(1)
template<class T>
void DownwardStack<T>::Pop()
{
assert(!IsEmpty());
size--;
}
// In order to put in something, the stack must not be full
// assert = 1 step
// IsFull = 1 step
// assignment = 1 step
// size++ = 1 step
// total = 4 steps
// O(1)
template<class T>
void DownwardStack<T>::Push(T val)
{
assert(!IsFull());
elements[FIXED_ARRAYED_STACK_CAPACITY - size - 1] = val;
size++;
}
template<class T>
void DownwardStack<T>::Clear()
{
size = FIXED_ARRAYED_STACK_CAPACITY;
assert(IsEmpty());
}
[/code]
I would implement this as
std::string reverse_string(std::string const & s) {
return {s.rbegin(), s.rend()}; // C++11 or later
return std::string(s.rbegin(), s.rend()); // historical dialects of C++
}
If you really must make life difficult for yourself by using a stack: push each character into it, then pop each out into the new string. By the nature of stacks, you'll pop the characters in the reverse order.
std::string reverse_string(std::string const & s) {
DownwardStack<char> stack;
// write a loop to push each character of "s" onto "stack"
std::string result;
// write a loop to pop each character from "stack" into "result"
return result;
}
If you absolutely have to return a unique pointer, (which you really, really shouldn't), then that becomes
std::unique_ptr<std::string> reverse_string(std::string const & s) {
DownwardStack<char> stack;
// write a loop to push each character of "s" onto "stack"
std::unique_ptr<std::string> result(new std::string);
// write a loop to pop each character from "stack" into "*result"
return result;
}
And do the world a favour: only use new when you actually need it. There's no reason to use unique_ptr either for the stack (make that automatic), or the return value (since std::string is movable).