Confused about returns in stack template

86 views Asked by At

I'm implementing a generic stack (with an array) in C++ and am confused about what to return in this situation:

template <class T>
T Stack<T>::pop(void) {
    if (size != 0) {
        return items[size - 1];
        size--;
    } else {
        cerr << "Cannot pop from empty stack." << endl;
        return ???;
    }
}

template <class T>
T Stack<T>::peek(void) {
    if (size != 0)
        return items[size - 1];
    else {
        cerr << "Cannot peek from empty stack." << endl;
        return ???;
    }
}

What are my options here? I think it would be messy to do something like declaring a new T variable and returning it. I'm drawing a blank.

2

There are 2 answers

0
Angew is no longer proud of SO On BEST ANSWER

This depends on what you want the behaviour (protocol) of your class to be. Since you're logging into the error stream there, I assume you consider this an error condition to call pop() on an empty stack. The standard C++ way of signalling errors is to throw an exception. Something like this:

template <class T>
T Stack<T>::pop(void) {
    if (size != 0) {
        size--;
        return items[size];
    } else {
        throw std::invalid_argument("Cannot pop from empty stack.");
    }
}

An alternative would be to say that pop() has a precondition "stack is not empty." Violation of a precondition is generally undefined behaviour, so you could simply assume the stack is not empty. This is the useful approach for performance-critical code:

template <class T>
T Stack<T>::pop(void) {
    asssert(size > 0);  // not necessary, but it's good practice to assert preconditions
    size--;
    return items[size];
}

The above two approaches assume that calling pop() on an empty stack is an error, i.e. that it shouldn't happen. If you instead want that to be a valid operation with a well-defined result, you have a few other options.

Return a flag indicating success:

template <class T>
std::pair<T, bool> Stack<T>::pop(void) {
    if (size != 0) {
        size--;
        return std::make_pair(items[size], true);
    } else {
        return std::make_pair(T(), false);  // requires T to be default-constructible
    }
}

Return a boost::optional:

template <class T>
boost::optional<T> Stack<T>::pop(void) {
    if (size != 0) {
        size--;
        return items[size];
    } else {
        return boost::none;
    }
}

Return a default-constructed T:

template <class T>
T Stack<T>::pop(void) {
    if (size != 0) {
        size--;
        return items[size];
    } else {
        return T();
    }
}
0
Vlad from Moscow On

Usually in such situations an exception is thrown.

Or you should change the return type of function pop to void.

As for the function peak then it could return a reference to an object in the stack.