Mahdi-bagvand
Mahdi-bagvand

Reputation: 1407

How can I return None in a function that has return type?

I have below code:

#include<iostream>
#include <vector>
using namespace std;
template<class T>
class Stack
{
private:
    vector<T> stack;

public:
    T Pop()
    {
        if (stack.size()!=0)
        {
            T temp;
            temp=stack[stack.size()-1];
            stack.erase(stack.begin()+stack.size()-1);
            return temp;
        }
        else
                   //return nothing
                   ^^^^^^^^^^^^^^^^
                   //How i can do above by code    
    }

In pop function: I want if stack.size==0; Pop function return nothing

How I can do it?

Upvotes: 3

Views: 7681

Answers (5)

Jon Purdy
Jon Purdy

Reputation: 54979

This is basically a question of how to handle non-total functions—functions that are not necessarily defined for all possible inputs. There are many ways to go about it, though none of them is type-safe:

  1. Have two separate functions for retrieving and erasing the top element of the stack, much like std::stack::top() and std::stack::pop().

  2. Use a reference parameter and return a bool indicating whether an element was returned:

    bool pop(T& value) {
      if (stack.empty())
        return false;
      value = stack.back();
      stack.pop_back();
      return true;
    }
    

    The caller can write:

    T value;
    if (stack.pop(value)) {
      use(value);
    }
    
  3. Return a boost::optional<T>.

  4. Return a default-constructed T instance. This requires that T be default-constructible, which is already imposed by some std::vector member functions.

  5. Throw an exception, documenting that a precondition was violated.

  6. Leave the behaviour of popping an empty stack undefined.

I recommend #1, #2, or #3, depending on preference and what fits best with the surrounding code.

Upvotes: 6

billz
billz

Reputation: 45410

You probably still want to do the same way as std::stack that to split into std::stack::top and std::stack::pop. You don't want to pop to return a value.

Here is the explaination from http://cpptruths.blogspot.com.au/2005/10/why-does-stdstackpop-returns-void.html

http://www.sgi.com/tech/stl/stack.html explains

[3] One might wonder why pop() returns void, instead of value_type. That is, why must one use top() and pop() to examine and remove the top element, instead of combining the two in a single member function? In fact, there is a good reason for this design. If pop() returned the top element, it would have to return by value rather than by reference: return by reference would create a dangling pointer. Return by value, however, is inefficient: it involves at least one redundant copy constructor call. Since it is impossible for pop() to return a value in such a way as to be both efficient and correct, it is more sensible for it to return no value at all and to require clients to use top() to inspect the value at the top of the stack.

std::stack < T > is a template. If pop() returned the top element, it would have to return by value rather than by reference as per the of above explanation. That means, at the caller side it must be copied in an another T type of object. That involves a copy constructor or copy assignment operator call. What if this type T is sophisticated enough and it throws an exception during copy construction or copy assignment? In that case, the rvalue, i.e. the stack top (returned by value) is simply lost and there is no other way to retrieve it from the stack as the stack's pop operation is successfully completed!

The practice way is to use pop(), top(), empty() together:

T top()
{
   return stack[size()-1];
}

void pop()
{
   stack.erase(stack.begin()+stack.size()-1);
}

usage:

if (!stack.empty())
{
    T t = top();
    pop();
}

Upvotes: 2

Emmanuel Valle
Emmanuel Valle

Reputation: 332

You can also do something like declare the pop method as void or even better, bool to get the status of the operation and pass the T type as an argument by reference in order to store the result in it:

bool Pop (T& item)
{
    if (stack.size() != 0)
       {
           // your code
           item = temp; // you can even use item instead of temp from the begining

           return true;
       }
    return false;
}

Upvotes: 1

Peter R
Peter R

Reputation: 2985

Here's one way of doing this. The idea is to package a Boolean flag together with the result in a tuple. The flag indicates whether there is a result or not. Notice though that the current implementation requires T to be default constructible.

template<class T>
class Stack
{
private:
    std::vector<T> stack;

public:
    typedef std::tuple<bool, T> return_t;

    void Push(const T& t)
    {
        stack.push_back(t);
    }

    return_t Pop()
    {
        if (stack.size()!=0)
        {
            T temp;
            temp=stack[stack.size()-1];
            stack.erase(stack.begin()+stack.size()-1);
            return std::make_tuple(true, temp);
        }
        else
            return std::make_tuple(false, T());
    }
};
int main()
{
    Stack<int> my_stack;
    bool has_result;
    int result;

    my_stack.Push(5);
    std::tie(has_result, result) = my_stack.Pop();
    std::cout << "has result = " << has_result << "\n";
    std::cout << "result = " << result << "\n";

    std::tie(has_result, result) = my_stack.Pop();
    std::cout << "has_result = " << has_result << "\n";
}

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409176

There are a couple of alternatives. One is to return an instance of T constructed with the standard constructor:

return T();

Another way would be to return a special sentinel wrapper object, that can be implicitly converted to T, and have a comparison operator so the user can check it.

Upvotes: 1

Related Questions