I am having trouble with stacking values for a deque object defined in a template class stack. When initializing a class stack object and use the push_back() member function of the STL deque class on the initialized object and read the number of elements inside the stack I get zero, yet the terminal told me it pushed values into it. It looks as follows:
Stack header file
#ifndef STACK_HH
#define STACK_HH
#include <iostream>
#include <deque>
template<class T>
class Stack {
public:
Stack(): s() { // <-- creating an empty deque s
s.size() ;
nitems() ;
empty() ;
}
~Stack() {
nitems() ;
empty() ;
}
//Member functions
int nitems() { return s.size() ; }
bool empty() { return (s.size()==0) ; }
void push_back(T c) {
s[s.size()] = c ;
}
T back() {
return s[s.size()] ;
}
void pop_back() {
if (empty()) {
std::cout << "Stack::pop() Error: stack is empty" << std::endl ;
}
}
private:
std::deque<T> s ;
};
#endif
Main script
#include <iostream>
#include <deque>
#include "Stack.h"
using namespace std ;
// Main
int main() {
int LEN = 10;
Stack<double> s ;
// Write doubles into Stack
for (int i=0 ; i<LEN ; i++) {
cout << "pushing value " << i*i << " in stack s" << endl ;
s.push_back(i*i) ;
}
// Count doubles in fifo
cout << s.nitems() << " value(s) in stack" << endl ;
return 0 ;
}
I was wondering if I should define the deque push_back(), back() and pop_back() functions differently in my Stack header file. Something like void deque < T > ::push_back() and similar for the other ones. But this did not solve it as I already was expecting yet using s.pushback() did not work either.
Any help in solving this problem is kindly appreciated.
EDIT:
Thank you all for the help.
You can indeed use directly the deque methods like that:
template<class T>
class Stack {
public:
Stack(): s() { // <-- creating an empty deque s
}
~Stack() {
}
//Member functions
int nitems() const { return s.size() ; }
bool empty() const { return s.empty() ; }
void push_back(const T& c) {
s.push_back(c) ;
}
const T& back() {
return s.back();
}
void pop_back() {
if (empty()) {
std::cout << "Stack::pop() Error: stack is empty" << std::endl ;
}
s.pop_back();
}
private:
std::deque<T> s ;
};
Why not std::stack?
Assigning to s[s.size()] doesn't add new elements:
Notes
Unlike std::map::operator[], this operator never inserts a new element into the container.
From http://en.cppreference.com/w/cpp/container/deque/operator_at.
Use s.push_back(new_element) to add new element.
Last element is s[s.size() - 1] or, better, s.back().
s.size(), s.size() and empty() in constructor and destructor do nothing.
Related
This question already has answers here:
Including .cpp files
(10 answers)
Why should I not include cpp files and instead use a header?
(14 answers)
Closed 2 years ago.
I have an error where "function already has a body" for my constructors and member functions when I have not repeated any of the bodies. The error code is C2084:
void Func(int);
void Func(int) {} // define function
void Func(int) {} // C2084 second definition
I have not created duplicate functions similar to what is shown on the visual studios error page. here is the code below if anybody knows a solution to this error I would greatly appreciate it.
Here is the Stack.h:
//CONTENTS: Declares Class SStack, with data members, contructors and member function prototypes
//If you want, you can make minor changes to this header file
#ifndef _StackClass_
#define _StackClass_
#include <cstdlib>
#include <string>
#include <iostream>
using namespace std;
class SStack
{
public:
// Constructor
SStack( int cap);
// Copy Constructor
SStack( const SStack& s );
~SStack( ); //destructor
// The member function push: Precondition: the stack is not full.
void push ( const std::string s);
// The member function pop: Precondition: the stack is not empty.
void pop ();
// The member function top: Precondition: the stack is not empty.
string top () const;
bool IsEmpty () const;
//printing all the elements in the stack
void print() const;
int size() const;
int getCapacity() const;
private:
int capacity; // Capacity is the maximum number of items that a stack can hold
std::string* DynamicStack;
int used; // How many items are stored in the stack
};
#include "SStack.cpp"
#endif
Here is the SStack.cpp:
#include <iostream>
#include "SStack.h"
SStack::SStack(int cap)
{
DynamicStack = new string[cap];
this->capacity = cap;
this->used = -1;
}
SStack::SStack(const SStack& s)
{
capacity = s.capacity;
DynamicStack = new string[capacity];
used = s.used;
for (int i = 0; i < used; i++) {
DynamicStack[i] = s.DynamicStack[i];
}
}
SStack::~SStack()
{
}
void SStack::push(const std::string s)
{
if (used >= capacity - 1) {
cout << "Stack overflow" << endl;
}
else {
this->used++;
DynamicStack[used] = s;
cout << s << "pushed onto the stack" << endl;
}
}
void SStack::pop()
{
if (used < 0) {
cout << "stack underflow" << endl;
}
else {
string s = DynamicStack[used];
this->used--;
}
}
string SStack::top() const
{
if (used < 0) {
cout << "stack is empty" << endl;
return 0;
}
else {
string s = DynamicStack[used];
return s;
}
}
bool SStack::IsEmpty() const
{
if (used < 0) {
return true;
}
else {
return false;
}
}
void SStack::print() const
{
for (int i = used; i >= 0; i--) {
cout << DynamicStack[used] << endl;
}
}
int SStack::size() const
{
return used;
}
int SStack::getCapacity() const
{
return capacity;
}
You have an #include "SStack.cpp" in your header file.
Don't do that.
Source files (.cpp files) include header files. Never the other way around.
I'm having a bit of trouble wrapping this around my head; I used the debugger in VS to go through my code. I realized that when I call the insertBack() function in main() the elements aren't inserted since the condition if (!isFull) isn't met--returning false causing the insertion to not happen. I tried removing the condition and got some errors regarding my code trying to insert a number into an invalid portion of the array. While going through this, I started to ask myself is the isFull() function required since a dynamic array can be resized; but, how can it be full if this is the case? I looked a bit into vectors on cpprefrence and didn't find an isFull() member function.
#include <iostream>
template<typename T>
class container
{
template <typename T2>
friend std::ostream& operator<<(std::ostream& out, const container<T2> &cobj);
// Postcondition: contents of the container object cobj is displayed
public:
container();
// Postcondition: an empty container object is created with data members arr set to NULL, n set to -1 and Capacity set to 0
~container();
// Destructor; required as one of the Big-3 (or Big(5) because of the presence of a pointer data member. Default version results in
// memory leak!
// Postcondition: dynamic memory pointed to by arr has been release back to the “heap” and arr set to NULL or nullptr
// In order to see the action, message "destructor called and dynamic memory released!" is displayed
bool isEmpty() const;
// Postcondition: returns true is nothing is stored; returns false otherwise
bool isFull() const;
// Postcondition: returns true if arr array is filled to capacity; returns false otherwise
int size() const;
// Postcondition: returns the size or the number of elements (values) currently stored in the container
int capacity() const;
// Postcondition: returns the current storage capacity of the container
bool insertBack(const T& val);
// Postcondition: if container is not full, newVal is inserted at the end of the array;
// otherwise, double the current capacity followed by the insertion
bool deleteBack();
// Precondition: The array must not be empty
// Postcondition: the last element stored in the array is removed! size of the container is decremented by 1, capacity unchanged
void clear();
// Postcondition: all elements in arr of calling container object are cleared and the dynamic memory is released back to “heap”
private:
void allocate(T* &temp);
// Postcondition: if Capacity = 0, allocate a single location; otherwise the current capacity is doubled
T *arr;
int Capacity; // Note: Capital 'C' as capacity is used as a function name
int n; // size or actual # of values currently stored in the container; n <= SIZE
};
template<typename T2>
std::ostream& operator<<(std::ostream& out, const container<T2> &cobj)
{
std::cout << "Currently it contains " << cobj.size() << " value(s)" << std::endl
<< "Container storage capacity = " << cobj.capacity() << std::endl
<< "The contents of the container:" << std::endl;
if (cobj.isEmpty())
{
std::cout << "*** Container is currently empty!" << std::endl;
}
else
{
for (int i=0; i<cobj.size(); ++i)
{
std::cout << cobj.arr[i];
}
}
return out;
}
template<typename T>
container<T>::container()
{
arr = nullptr;
Capacity = 0;
n = 0;
}
template<typename T>
container<T>::~container()
{
delete arr;
arr = nullptr;
std::cout << "Destructor called! (this line is normally not displayed)" << std::endl;
}
template<typename T>
bool container<T>::isEmpty() const
{
return n==0;
}
template<typename T>
bool container<T>::isFull() const
{
return n==Capacity;
}
template<typename T>
int container<T>::capacity() const
{
return Capacity;
}
template<typename T>
int container<T>::size() const
{
return n;
}
template<typename T>
bool container<T>::insertBack(const T& val)
{
if (!isFull())
{
n++;
arr[n-1] = val;
return true;
}
else
{
return false;
}
}
template<typename T>
bool container<T>::deleteBack()
{
if (!isEmpty())
{
n--;
return true;
}
else
{
return false;
}
}
template<typename T>
void container<T>::clear()
{
if (!isEmpty())
{
n = 0;
return true;
}
else
{
return false;
}
}
template<typename T>
void container<T>::allocate(T* &temp)
{
if (Capacity==0)
{
temp = new T;
}
else
{
return Capacity*2;
}
}
int main()
{
container<int> a1;
std::cout << a1 << std::endl;
std::cout << "Currently, the container object contains 0 element(s) or 0 value(s)" << std::endl;
std::cout << "\nWe now insert 3 values at the back of the array, one at a time:" << std::endl;
const int num = 3;
for (int i=0, c=0; i<=num; ++i, c+=10)
{
a1.insertBack(c);
}
std::cout << a1;
}
I think that having an isFull method does not make sense, since your dynamic container is not limited in capacity. Instead, you can use the size and capacity methods to track the state of the container.
If you want to implement a vector and want to check if size smaller than or equals to capacity, then decide whether to resize it, you can wrapper size > = capacity as a private isFull() function. But I think it makes no sense to set it public.
I have the following main program that creates a Stack object, fills it with doubles and then pops them. The code files fine, but the pop_back() part does not seem to work, while s.back() does return the correct value. How is this possible?
#include "Stack.h"
#include <iostream>
#include <deque>
using namespace std;
int main() {
Stack<double> s(0,0.0);
// Write doubles into Stack
int i ;
for (i=0 ; i<15 ; i++) {
s.push(i*i) ;
}
// Read doubles back from fifo
while (!s.empty()) {
double val = s.pop() ;
std::cout << "Popping value " << val << " from stack" << std::endl ;
}
return 0 ;
}
My header file looks like this, where I have omitted parts which are not relevant to the question.
#ifndef STACK_H
#define STACK_H
#include <iostream>
#include <deque>
template<class T>
class Stack {
public:
Stack(int len, T defval): s(len+1, defval) {
return;
}
~Stack() {
//delete [] s;
}
void push(T c) {
s.push_back(c);
}
T pop() {
return s.back();
s.pop_back();
}
private:
std::deque<T> s; //Array<T> s;
};
#endif
T pop() {
return s.back();
// ^^^^^
s.pop_back(); // <- unreachable!
}
When you return from a function, all the subsequent instruction will never be executed.
Store s.back()'s result in a temporary variable instead:
T pop() {
auto back = s.back();
s.pop_back();
return back;
}
I am little lost with templates, and how compiler processes them.
Needed some generic wrapper for std::vector<< SomeType * >>* lpVars; that is capable of performing delete on all items contained inside that vector when I delete lpVars. Something similar to the C#'s List<> (generic list class).
So I went for templates and wrote something like this:
template<class T>
class ListPtr
{
public:
std::vector<T*> items;
ListPtr()
{ }
~ListPtr()
{
size_t count = items.size();
for(size_t i=0; i<count; i++)
{
T* item = items[i];
delete item;
}
items.clear();
}
inline const int count() const
{
return (int)items.size();
}
inline T* operator[](size_t index) const
{
return items[index];
}
inline void Add(T* item)
{
items.push_back(item);
}
};
later on I declared global type lists like:
class SomeType1List : public ListPtr<SomeType1> {};
class SomeType2List : public ListPtr<SomeType2> {};
...
class SomeTypeNList : public ListPtr<SomeTypeN> {};
Here is the first part of my interest on subject:
(1) Are this classes SomeType1List, SomeType1List, ..., SomeTypeNList fully preprocessed to templates code with replaced T template type for each declaration (SomeType1, SomeType2, ..., SomeTypeN) like there is no template (are fully declared classes), or compiler performs some other magic here?
(2) And if compiler performs some other magic, how should I define this types that compiler would compile them as they are fully declared classes?
To explain usage of above code more precise:
this list instances are initialized, and returned from functions like following one:
SomeType1List* GetItems()
{
SomeType1List* items = new SomeType1List();
for(int i=0; i<1000; i++)
{
SomeType1* item = new SomeType1();
// feed item with some data
items->Add(item);
}
return items;
}
and used in other parts of code like this:
SomeType1List* items = GetItems();
int count = items->count();
for(int i=0; i<count; i++)
{
SomeType1* item = items[i];
// do something with item;
}
delete items; // all memory occupied by items released after this line
Second part of my interest on subject:
(3) Could this be written differently using only standard classes (no boost or similar sdks)? goal is speed but to keep code clean and easy to read. So this question would be is there any better way to do all of this?
Yes
No magic here
You can use std::vector<std::unique_ptr<T>> (C++11) or std::vector<std::auto_ptr<T>> (kind of deprecated)
Example:
#include <iostream>
#include <memory>
#include <vector>
class T
{
private:
unsigned int _i;
public:
void print() const
{
std::cout << "Print: " << _i << std::endl;
}
T(unsigned int i)
{
_i = i;
std::cout << "Constructor! " << _i << std::endl;
}
~T()
{
std::cout << "Destructor! " << _i << std::endl;
}
};
std::vector<std::unique_ptr<T>>* createStuff()
{
auto output = new std::vector<std::unique_ptr<T>>;
for(unsigned int i = 0; i < 5; i++)
{
output->emplace_back(new T(i));
}
return output;
}
int main()
{
std::cout << "Begin!" << std::endl;
auto stuff = createStuff();
for(std::unique_ptr<T> const& thing : *stuff)
{
thing->print();
}
delete stuff;
std::cout << "End!" << std::endl;
return 0;
}
Output:
Begin!
Constructor! 0
Constructor! 1
Constructor! 2
Constructor! 3
Constructor! 4
Print: 0
Print: 1
Print: 2
Print: 3
Print: 4
Destructor! 0
Destructor! 1
Destructor! 2
Destructor! 3
Destructor! 4
End!
I have a very silly problem that I just can't figure out. I'm trying to overload the << operator in my "PrioQueue" class. I'm still pretty new to C++ and i've tried almost every example I could find on the web but nothing works.
The PrioQueue is a template class I made that works like a normal Queue but puts the highest value it receives on the top.
PrioQueue<int> intq1(5);
intq1.push(1);
intq1.push(2);
intq1.push(1);
cout << intq1;
The << operator should write all the values that I've pushed to the queue with a '|' in between. So like this:
2 | 1 | 1 |
This is my overload operator << method.
friend std::ostream& operator<<(std::ostream& out, PrioQueue q){
while(!q.empty()){
out.write(q.pop()); //This method pops off the top value and returns it
}
return out;
}
I hope this is enough information but if not. This is my full code:
#include "stdafx.h"
#include <iostream>
#include <ostream>
using namespace std;
template <typename Type>
class PrioQueue
{
private:
Type *bottom_;
Type *top_;
int size_;
public:
PrioQueue(Type size){
bottom_ = new Type[size];
top_ = bottom_;
size_ = size;
}
friend PrioQueue operator+(PrioQueue q1, PrioQueue q2){
while(!q2.empty()){
q1.push(q2.pop());
}
return q1;
}
friend std::ostream& operator<<(std::ostream& out, PrioQueue q){
while(!q.empty()){
out.write(q.pop());
}
return out;
}
//Checks to see if the given value is bigger than the bottom character.
//If so, the bottom and the given value swap places.
//If not, the value gets placed at the top of the queue
void push(Type t){
if(*bottom_ < t){
*top_ = *bottom_;
*bottom_ = t;
}else{
*top_ = t;
}
top_++;
}
int num_items() {
return (top_ - bottom_);
}
Type pop(){
return *(bottom_++);
}
int full() {
return (num_items() >= size_);
}
int empty() {
return (num_items() <= 0);
}
void print(){
cout << "Queue currently holds " << num_items() << " items: " ;
for (Type *element=top_-1; element >= bottom_; element--) {
cout << " " << *element;
}
cout << "\n";
}
int getSize(){
return size_;
}
~PrioQueue(){ // stacks when exiting functions
bottom_ = 0;
delete[] bottom_;
}
};
void intExample(){
PrioQueue<int> intq1(5);
intq1.push(1);
intq1.push(2);
intq1.push(1);
cout << intq1;
intq1.print();
PrioQueue<int> intq2(5);
intq2.push(8);
intq2.push(2);
intq2.push(5);
intq2.print();
PrioQueue<int> intq3(10);
intq3 = intq1 + intq2;
intq3.print();
cout << intq3;
}
void charExample(){
PrioQueue<char> charq1(5);
charq1.push('t');
charq1.push('h');
charq1.push('g');
charq1.print();
PrioQueue<char> charq2(5);
charq2.push('i');
charq2.push('q');
charq2.push('k');
charq2.print();
PrioQueue<char> charq3(10);
charq3 = charq1 + charq2;
charq3.print();
}
int main(){
intExample();
charExample();
return 0;
}
This would work:
friend std::ostream& operator<<(std::ostream& out, PrioQueue q){
while(!q.empty()){
out << q.pop() << "|";
}
return out << "\n"; // if you want a newline, otherwise just "return out;"
}
Edit Note that for this to work, you will have to modify your queue to be copyable. You need to add a copy constructor and an assignment operator (see the rule of three) or use a type that is copyable and assignable to store your data (see std::vector, std::deque, or container adapter std::priority_queue if this is not an exercise).
The problem is that the out.write() expects a const char* and size. First of all, your Type will not implicitly convert to const char* and also, you're missing an argument.
Using out << q.pop() will fix the problem for you.