Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moving underlying container (std::vector or std::deque) for std::stack and std::queue [duplicate]

I had a usecase where I use a stack to process some data. Once processed, I want to output the data as a vector. But since underlying containers in stack are protected, it is now allowed to:

stack<int, vector<int>> st;
// Some stack operations
vector<int> v(move(st));

This entails that the copy must necessarily happen. Is there a way to get around this, without using custom stack? (I want the application to be portable, so no changes to STL lib are good)

I tried compiling the above code, and it obviously threw compile time error as the underlying container is not exposed.

like image 743
Dwij Dixit Avatar asked Dec 22 '25 13:12

Dwij Dixit


2 Answers

Use helper that exposes the adaptor’s protected c and moves it out

#include <stack>
#include <vector>
#include <iostream>
#include <utility>

template<class T, class C>
C take_container(std::stack<T, C>&& st) {
    struct exposed : std::stack<T, C> {
        using std::stack<T, C>::c; // expose protected member
        explicit exposed(std::stack<T, C>&& s)
            : std::stack<T, C>(std::move(s)) {}
    };
    exposed tmp(std::move(st));    // take ownership of adaptor
    return std::move(tmp.c);       // move out the underlying container
}

int main() {
    std::stack<int, std::vector<int>> st;
    for (int x : {1,2,3,4,5}) st.push(x); // bottom..top = 1,2,3,4,5

    std::vector<int> v = take_container<int, std::vector<int>>(std::move(st));

    std::cout << "vector: ";
    for (int x : v) std::cout << x << " ";
    std::cout << "\n";
}

https://godbolt.org/z/ohvhq7T78

WHAT THE TRICK DOES

std::stack<T,C> is an adaptor around an underlying container C . The C++ standard mandates that these adaptors store that container in a protected data member named c.

Because it is protected, you cannot access st.c from ordinary code. But a class that derives from std::stack<T,C> may access c. So I make a tiny derived helper type that:

  • inherits from std::stack<T,C>,

  • brings c into scope with a using declaration,

  • move-constructs itself from your std::stack<T,C>,

  • then it returns std::move(tmp.c); to move the underlying container out.

This gives you the container by move, without copying elements.

CONSTRAINTS AND CAVEATS

  • Works for any C that is movable (vector, deque, list, etc.). If C is not movable, this will not compile.

  • Do not use st after calling take_container(std::move(st)). It is moved-from; you may only destroy or assign to it.

  • This relies on the adaptor’s protected member name c. That is mandated by the standard for adaptor classes and has been stable across C++ versions.

  • Exception safety: you can make the function noexcept if moving C is noexcept

like image 198
0___________ Avatar answered Dec 24 '25 03:12

0___________


You might inherit from std::stack to expose the underlying container:

template <typename T>
struct myStack : std::stack<T, std::vector<T>>
{
    using std::stack<T, std::vector<T>>::c; // underlying container
    // probably better to create dedicated method as extract()
    // instead of exposing it directly though
};

and then

myStack<int> st;

// Some stack operations

std::vector<int> v(std::move(st.c));

Demo

like image 44
Jarod42 Avatar answered Dec 24 '25 03:12

Jarod42



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!