0

For my course, I'm asked to create a Stack class that stores its elements in a STL container (but not the STL stack container).

Requirements:

  • must be able to store elements of an arbitrary type
  • every instance accepts insertions as long as the system has enough free memory
  • must be in namespace cop4530
  • must use most of the methods and operator overloads shown in header file below (not back(), +=op, []ops)
  • methods/functions, etc declared in .h, and implemented in separate .hpp

I then use the stack with another program I create that changes infix notation arithmetic to postfix, and evaluates it if all the elements are comparable.

My professor gave an example header file of what this may look like, which is shown below.

Why does he use a deque pointer?? I've searched and found many cases where people adapt a STL container to a stack, but never an explanation for a STL container as a pointing to a stack. Could someone explain the benefits of this over using a non pointer, if there are any? Examples help

Example .h declaration file

#ifndef COP4530_STACK_H
#define COP4530_STACK_H

#include <iostream>
#include <deque>

namespace cop4530
{

template <typename T>
class Stack;

//----------------------------------
//     Stack<T>
//----------------------------------

template <typename T>
class Stack
{
public:
  // Constructor, Copy-constructor and destructor
  Stack  ();
  Stack  (const Stack<T>&);
  Stack  (Stack<T> &&);
  ~Stack (); 

  // member operators
  Stack<T>& operator =  (const Stack<T>&);
  Stack<T> & operator=(Stack<T> &&);
  Stack<T>& operator += (const Stack<T>&);
  const T&         operator [] (int) const;
  T&               operator [] (int);

  // other methods
  int   size        () const;
  int   capacity    () const;

  // Container class protocol
  bool         empty     () const;
  void         clear     ();
  void         push      (const T&);
  void         push      (T &&);
  void         pop       ();
  T&           top       ();
  const T&     top       () const;
  T&           back      ();


  // Display methods 
  void print    (std::ostream& os, char ofc = ' ') const;

protected:
  std::deque<T>  *mystack;   // pointer to the stack.
//std::deque<T>   mystack;   //WHY NOT THIS???

} ;

// operator overloads
template < class T >
std::ostream& operator << (std::ostream& os, const Stack<T>& a);

template < class T >
bool      operator == (const Stack<T>&, const Stack<T>&); 

template < class T >
bool      operator != (const Stack<T>&, const Stack<T>&); 

template < class T >
bool      operator <= (const Stack<T>&, const Stack<T>&);

#include "stack.hpp"

}   // namespace cop4530
#endif

Example .hpp implementation

#ifndef COP4530_STACK_HPP
#define COP4530_STACK_HPP

//----------------------------------------
//     Stack<T>:: Implementations
//----------------------------------------

// operator overloads

    template <typename T>
std::ostream& operator << (std::ostream& os, const Stack<T>& s)
{

}

    template <typename T>
bool operator<=(const Stack<T>& s1, const Stack<T>& s2)
{

}

    template <typename T>
bool operator == (const Stack<T>& s1, const Stack<T>& s2)
{

}

    template <typename T>
bool operator != (const Stack<T>& s1, const Stack<T>& s2)
{

}

// public methods

    template <typename T>
Stack<T>::Stack()
    //Constructor
{

}

    template <typename T>
Stack<T>::Stack(const Stack<T>& source)
    //Copy-constructor
{

}


template <typename T>
Stack<T>::Stack(Stack<T> && source)
{

}
    template <typename T>
Stack<T>::~Stack()         
    // destructor
{

}

    template <typename T>
Stack<T>& Stack<T>::operator = (const Stack<T>& source) 
    // assignment operator
{

}

template <typename T>
Stack<T>& Stack<T>::operator = (Stack<T> && source)
{

}

    template <typename T>
Stack<T>& Stack<T>::operator += (const Stack<T>& source) 
{

}

template <typename T>
const T& Stack<T>::operator [] (int i) const                 
// element operator
{

}

    template <typename T>
T& Stack<T>::operator [] (int i)
    // element operator
{

}

template <typename T>
bool Stack<T>::empty() const
{

}

template <typename T>
int Stack<T>::size() const
{

}

    template <typename T>
void Stack<T>::push(const T& Val)
{

}

template <typename T>
void Stack<T>::push(T && Val)
{

}

    template <typename T>
void Stack<T>::pop()
{

}

    template <typename T>
void Stack<T>::clear()
{

}

template <typename T>
T&  Stack<T>::top()
{

}

template <typename T>
const T&  Stack<T>::top() const
{

}

template <typename T>
T&  Stack<T>::back()
{

}

template <typename T>
void Stack<T>::print(std::ostream& os, char ofc) const
{

}

#endif
Viktor R.
  • 1
  • 1
  • For shallow copy? – kwjsksai Oct 25 '16 at 14:30
  • I think your professor is weird - `back` is not normally a stack operation. A "normal" stack implementation wouldn't have `back`, and use an underlying `std::vector`. (Not a pointer.) – molbdnilo Oct 25 '16 at 14:47
  • @molbdnilo lol, I know **back** isn't a standard stack operation, I plan to ask a TA about that one tomorrow. What are your reasons for using **std::vector** over **std::deque**? Wouldn't that be more expensive? – Viktor R. Oct 25 '16 at 15:11
  • @molbdnilo: Using a `deque` rather than `vector` might be reasonable if the elements are expensive to copy. With `vector` you copy everything each time it has to expand its capacity, but with `deque` you avoid this. – John Zwinck Oct 25 '16 at 15:28
  • @JohnZwinck Yeah, you're right of course. I have a memory leak. – molbdnilo Oct 25 '16 at 15:37
  • std::deque supports move semantics according to cppreference, so I don't see any reason to use an internal pointer. If there is a reason, I'd like to know, too. Maybe its a workaround for a specific compiler and std implementation which doesn't fully support c++11? – Kenny Ostrom Oct 25 '16 at 16:08

0 Answers0