4

I need to put an std::vector into an std::stack.

Here is my method so far(I am building a card game) :

void CardStack::initializeCardStack(std::vector<Card> & p_cardVector) {
   m_cardStack = std::stack<Card>();
   //code that should initialize m_cardStack with p_cardVector
}

Note : I cannot change my method signature because it is a imposed by a teacher...

Do I have to iterate over the whole vector ? What is the most efficient way to do this ? The documentation.

I have tried Jens answer but it didn't work.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
AlexB
  • 3,518
  • 4
  • 29
  • 46
  • 1
    Either pass the vector by const-reference, because it does not get modified, or by value and move the contents into the stack. The last version allows the compiler to generate more efficient code in same cases. – Jens Sep 27 '15 at 06:56
  • A `std::stack<....>` of what? By default, `stack` uses a `deque`, not a `vector`, as its underlying container. – T.C. Sep 27 '15 at 07:05
  • See my edit. I added more context. – AlexB Sep 27 '15 at 07:08
  • The constructor you mention does not work because it expects an argument of stack::container_type, which is std::deque by default. It is not a template-constructor which accepts any container type. You have to create a temporary container, just as I do in my answer. – Jens Sep 27 '15 at 16:28

2 Answers2

4

std::stack doesn't have a constructor which accepts iterators, so you could construct a temporary deque and initialize the stack with this:

void ClassName::initializeStack(std::vector<AnotherClass> const& v) {
   m_stackAttribute = std::stack<AnotherClass>( std::stack<AnotherClass>::container_type(v.begin(), v.end()) );
}

However, this copies each element into the container. For maximum efficiency, you should also use move-semantics to eliminate copies

void ClassName::initializeStack(std::vector<AnotherClass>&& v) {
   std::stack<AnotherClass>::container_type tmp( std::make_move_iterator(v.begin()), std::make_move_iterator( v.end() ));
   m_stackAttribute = std::stack<AnotherClass>( std::move(tmp) );
}
Jens
  • 9,058
  • 2
  • 26
  • 43
  • This code doesn't work for me. I am looking at the documentation and I found this method signature move-initialize (2) explicit stack (container_type&& ctnr = container_type()); – AlexB Sep 27 '15 at 16:01
  • @AlexB Fixed it. The template arguments for the stacks were missing. Working code at http://cpp.sh/8l7kk. – Jens Sep 27 '15 at 16:14
  • It compiles but the size is 0. The stack doesn't get filled with the vector values – AlexB Sep 27 '15 at 16:59
  • @AlexB In the example code, the first vector was empty, so the stack has to be empty. If you add something to the vector, the stack has the same size: http://cpp.sh/2mss – Jens Sep 27 '15 at 17:01
0

The most efficient way is not using an std::stack at all and just use a std::vector or even better for this use a std::deque.

I've seen and written a lot of C++ code (a lot) but I've yet to find any use for the stack stuff (any meaningful use, that is). It would be different if the underlying container could be changed or having its container type determined at runtime, but this is not the case.

To copy the elements from an std::vector into a std::deque you can just use

std::deque<T> stack(vec.begin(), vec.end());

This will allow the implementation to use the most efficient way to copy the elements.

To explicitly answer your question: yes, the only way to put elements in a stack is to push them in with a loop. This is not efficient but the stack interface doesn't define anything else. However who wrote code accepting an std::stack parameter should be fired (unless s/he promises that it will never happen again) and its code reverted to something more sensible: you would get the same (absence of) "flexibility" but a better interface.

The design problem of stack is that it's parametrized on the underlying container type while instead (to have any meaning) should have been parametrized on the contained element type and receving in the constructor a container for that type (thus hiding the container type). In its present form is basically useless.

6502
  • 112,025
  • 15
  • 165
  • 265
  • 2
    I think ´std::stack`and `std::deque` have one advantage over using the underlying container directly. They express the intend of using a stack, and when I look at the code I see immediatly that a stack used. With a `vector`, I have to figure out how it is used, or look at hopefully existing comments. So I would say that besides from other issues, they at have a very useful meaning. – Jens Sep 27 '15 at 06:59
  • 1
    @Jens: `std::deque` is a container, not an adapter, and it's very useful. `std::stack` on the other side just removes methods without providing anything. Providing minimal interfaces is sometimes useful, but only if you can hide/shield the real provider; this is the work of interfaces (but `std::stack` is not an interface because the underlying container is contained, not referenced, and its type must be known compile time removing any flexibility that an interface would add). – 6502 Sep 27 '15 at 08:12
  • 2
    Stack and queue may not provide functionality, but they express intent. I find this usefull when reading code. This also expresses the contract of functions very clearly at the type level. But I agree that it would be better to have a concept stack or queue in the STL, and deque should be a model for queue. Or maybe a type-erased wrapper which expresses that intent. I just wouldn't say it's completely useless. – Jens Sep 27 '15 at 10:14