是否有关于std::stack元素销毁顺序的保证?

我有一个类,负责管理一组服务的生命周期。由于可能存在服务相互依赖关系,因此构造和销毁的顺序很重要-应该以与创建服务相反的顺序销毁服务。

我以为我会为此目的使用std::stack<std::unique_ptr<Service>>。我知道堆栈是容器适配器,并猜测这可能会影响其破坏语义,因此我进行了搜索,但I couldn't find any documentation(第800页)确保了std::stack元素的破坏顺序。

最后,我编写了一个小测试:

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;
}

结果符合预期:
Destroying instance 3
Destroying instance 2
Destroying instance 1
...done

我应该依靠这种行为吗?是为std::stack保证了天真的销毁顺序,还是我应该采取将其弹出直到明确的步骤(非常简单)?

最佳答案

std::stack 不是容器,而是容器适配器。它以您实际上要使用哪个容器存储元素作为第二个参数:

template<
    class T,
    class Container = std::deque<T>
> class stack;
stack<T>的销毁语义将是deque<T>的销毁语义。但是,这并没有真正帮助您,因为deque<T>的销毁顺序未由标准指定。实际上,没有为任何序列容器指定它。

如果销毁顺序很重要,那么您应该执行以下两项操作之一:提供一个新容器,该容器首先销毁其元素:
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>>;

或提供自己的stack实现,其析构函数弹出所有元素:
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();
        }
    }
};

09-04 16:04
查看更多