Is there any guarantee regarding the destruction order of std::stack elements?
I have a class that manages the lifetime of a set of services. Since there may be service interdependencies, the order of construction and destruction is important -- the services should be destroyed in the reverse order of their creation.
I thought I would use a std::stack<std::unique_ptr<Service>>
for this purpose. Knowing that a stack is a container adapter, and guessing that this might affect its destruction semantics, I searched, but I couldn't find any documentation (page 800) that guaranteed the order of destruction for the elements of a std::stack.
In the end, I wrote a little test:
struct Squealer {
Squealer() {
static int instance_count = 0;
this->instance = ++instance_count;
}
~Squealer() {
std::cout << "Destroying instance " << instance << std::endl;
}
int instance;
};
int main(int argc, char *[] argv) {
{
std::stack<Squealer> squealers;
squealers.emplace();
squealers.emplace();
squealers.emplace();
}
std::cout << "...done" << std::endl;
}
The result was as expected:
Destroying instance 3
Destroying instance 2
Destroying instance 1
...done
Should I be relying on this behavior? Is the naive destruction order guaranteed for std::stack, or should I take the (admittedly easy) step of popping it until it is clear?
std::stack
isn't a Container, it's a Container Adapter. It takes as its second parameter which Container you actually want to use to store the elements:
template<
class T,
class Container = std::deque<T>
> class stack;
The destruction semantics of stack<T>
would be those of deque<T>
. This, however, doesn't really help you very much, since the destruction order of deque<T>
is unspecified by the standard. Indeed, it's not specified for any of the sequence containers.
If destruction order is important, then you should do one of two things: either provide a new container that destroys its elements last to first:
template <class T>
struct my_deque : std::deque<T>
{
using std::deque<T>::deque;
~my_deque() {
while (!this->empty()) this->pop_back();
}
};
template <class T>
using my_stack = std::stack<T, my_deque<T>>;
Or provide your own implementation of stack
whose destructor pops all the elements:
template <class T, class Container = std::deque<T>>
struct ordered_stack : std::stack<T, Container>
{
using std::stack<T, Container>::stack;
~ordered_stack() {
while (!this->empty()) {
this->pop();
}
}
};
By default a stack
is backed by a deque
(23.6.6.1)
template <class T, class Container = deque<T>>
class stack {
A deque
does not have a defined destruction order.
However, you can implement a simple container that supports the stack
, you just need to provide back
, push_back
, and pop_back
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With