12

I need to copy std::vector into std::stack.

  1. Is traversing over vector and pushing into stack is only the way?

  2. If there is another way what is better choice from performance point of view?

code:

 std::stack<A>   m_stack;
 std::vector<A>  m_vec;

 for (auto& elem : m_vec)
 {
    m_stack.push(elem);
 }
alfC
  • 14,261
  • 4
  • 67
  • 118
T M
  • 3,195
  • 2
  • 31
  • 52

4 Answers4

17

Since a stack is a container adaptor, you can create the stack from the underlying container:

std::vector<A> m_vec = /* ... */;
std::stack<A, std::vector<A>> m_stack(m_vec);

Or, if you want your stack to be deque-backed:

std::stack<A> m_stack(std::deque<A>(m_vec.begin(), m_vec.end()));
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • will a copying be happened here ? – Humam Helfawi Dec 24 '15 at 12:38
  • @HumamHelfawi: Yes. I assumed the OP wanted that, since she said "I need to copy". You can also move the vector in if you don't need the original any longer. – Kerrek SB Dec 24 '15 at 12:44
  • @KerrekSB Thanks, I was just asking not criticizing :) I voted up before commenting;) – Humam Helfawi Dec 24 '15 at 13:07
  • @basav why not? std::containers are move-aware like almost everything else in the std library – Richard Hodges Dec 24 '15 at 13:35
  • @basav: I don't understand your comment. The OP wants to copy data, which is what we're doing. The temporary deque in the second example is already using the rvalue stack constructor. If the original vector was no longer needed, you could move it into the stack in the first example and use move iterators in the second. – Kerrek SB Dec 24 '15 at 13:41
  • Hi guys, one more thing. what if the stack is already there and it is needed to append data from vector to stack? – T M Dec 24 '15 at 13:47
  • 1
    @TM: You can't do that other than with a loop, or possibly deriving your own adaptor and adding such a facility. Check [the documentation](http://en.cppreference.com/w/cpp/container/stack) for the (very short) interface to learn what you can and cannot do. If the bill doesn't fit, don't bother using a stack, and just use a vector and operate it *like* a stack. There's no prize for using `std::stack` at any cost. – Kerrek SB Dec 24 '15 at 14:11
2

Some fun with stacks demonstrating various methods of getting values onto the stack from another container.

Assuming we provided an appropriate definition for:

template<class T, class Container>
auto stack_pusher(std::stack<T, Container>& stack);

We could then write:

int main()
{
    using namespace std;

    // construct an initial vector
    vector<int> init { 7,6 };

    // construct a stack using a copy of the initial vector's elements
    // note that the stack's storage is automatically deduced
    stack<int> stack1 { { begin(init), end(init) } };

    // construct a stack directly from a container initialised with an initialiser list
    stack<int> stack2 { { 3,4,5 } };

    // another vector
    vector<int> myvector { 1, 2, 3, 4, 5, 6, 7, 8 };

    // copy vector onto stack using a forward iterator
    copy(begin(myvector),
         end(myvector),
         stack_pusher(stack1));

    // copy vector onto stack using a reverse iterator
    copy(rbegin(myvector),
         rend(myvector),
         stack_pusher(stack2));

    // display the stacks
    while (stack1.size() or stack2.size())
    {
        // function to encode an optional T as a string
        auto encode = [](const auto& opt)
        {
            return opt ? std::to_string(opt.value()) : std::string("*");
        };

        // function to pop a value from a stack if it's not empty.
        // return an optional
        auto maybe_pop = [](auto& stack)
        {
            using element_type = std::decay_t<decltype(stack.top())>;
            boost::optional<element_type> result;
            if (stack.size()) {
                result = stack.top();
                stack.pop();
            }
            return result;
        };

        cout
        << encode(maybe_pop(stack1))
        << "\t"
        << encode(maybe_pop(stack2)) << endl;
    }

    return 0;
}

for which the output would be:

8       1
7       2
6       3
5       4
4       5
3       6
2       7
1       8
6       5
7       4
*       3

Here's the full listing (c++14):

#include <iostream>
#include <stack>
#include <vector>
#include <deque>
#include <iterator>
#include <utility>
#include <boost/optional.hpp>

// an iterator that pushes values onto a stack
template<class Stack>
struct push_iterator
: std::iterator<std::output_iterator_tag,void,void,void,void>
{
    push_iterator(Stack& stack)
    : pstack(std::addressof(stack))
    {}

    template<class T>
    auto& operator=(T&& t)
    {
        pstack->push(std::forward<T>(t));
        return *this;
    }

    auto& operator*() {
        return *this;
    }

    auto& operator++() {
        return *this;
    }

private:
    Stack* pstack;
};

// convenience class to make a push_iterator of the correct type
template<class T, class Container>
auto stack_pusher(std::stack<T, Container>& stack)
{
    return push_iterator<std::stack<T, Container>>(stack);
}

int main()
{
    using namespace std;

    // construct an initial vector
    vector<int> init { 7,6 };

    // construct a stack using a copy of the initial vector's elements
    // note that the stack's storage is automatically deduced
    stack<int> stack1 { { begin(init), end(init) } };

    // construct a stack directly from a container initialises with an initialiser list
    stack<int> stack2 { { 3,4,5 } };

    // another vector
    vector<int> myvector { 1, 2, 3, 4, 5, 6, 7, 8 };

    // copy vector onto stack using a forward iterator
    copy(begin(myvector),
         end(myvector),
         stack_pusher(stack1));

    // copy vector onto stack using a reverse iterator
    copy(rbegin(myvector),
         rend(myvector),
         stack_pusher(stack2));

    // display the stacks
    while (stack1.size() or stack2.size())
    {
        // function to encode an optional T as a string
        auto encode = [](const auto& opt)
        {
            return opt ? std::to_string(opt.value()) : std::string("*");
        };

        // function to pop a value from a stack if it's not empty.
        // return an optional
        auto maybe_pop = [](auto& stack)
        {
            using element_type = std::decay_t<decltype(stack.top())>;
            boost::optional<element_type> result;
            if (stack.size()) {
                result = stack.top();
                stack.pop();
            }
            return result;
        };

        cout
        << encode(maybe_pop(stack1))
        << "\t"
        << encode(maybe_pop(stack2)) << endl;
    }

    return 0;
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
1

std::stack is a strange but hackeable container:

#include<vector>
#include<stack>

struct A{};

template<class T>
struct mystack : std::stack<T>{
    decltype(auto) c(){return std::stack<T>::c;}
};

int main(){
    std::vector<A>  m_vec;

    mystack<A>   m_stack;
    m_stack.c().assign(m_vec.begin(), m_vec.end());

}

or

#include<vector>
#include<stack>

struct A{};

template<class... T>
struct mystack : std::stack<T...>{
    decltype(auto) container(){return std::stack<T...>::c;}
};

template<class... T>
decltype(auto) container(std::stack<T...>& s){return static_cast<mystack<T...>&>(s).container();}

int main(){
    std::vector<A>  m_vec;

    std::stack<A>   m_stack;
    container(m_stack).assign(m_vec.begin(), m_vec.end());
}
alfC
  • 14,261
  • 4
  • 67
  • 118
0

See this question for ways of allowing std::copy to be used on a stack, but out of the box, there is no more obvious way than a loop with calls to push.

As to performance, the only way to tell is to measure it. (Code for clarity and correctness first, and then worry about speed.)

Community
  • 1
  • 1