Да, это безопасно, если вы используете неконстантную версию стека. (Для константной версии стека вы, скорее всего, скопируете объект или получите ошибку компиляции)
Поскольку std::stack
возвращает неконстантную ссылку на объект, вы можете изменить его. Это включает в себя перемещение от объекта.
Напомним, что перемещение от объекта сохраняет его в допустимом состоянии (по крайней мере, если класс реализован правильно). Это не уничтожает его. Это все еще там на вершине вашего стека. Это просто не содержит никакой определенной ценности. Последующие действия pop
без проблем вызовут для него надлежащий деструктор.
Обратите внимание, что вывоз не разрешен для std::priority_queue
, поскольку контейнер такого типа на самом деле заботится о содержании. И - по этой причине он просто возвращает константную ссылку, которая не может быть использована для удаления вещей из нее.
В ответ на наблюдение Яманона о том, что std::move
может быть выполнено на константной ссылке. На самом деле вы можете сделать это. Обычно это бесполезно, хотя обычно сокращается до копии вместо перемещения. Рассмотрим следующий пример:
#include <iostream>
#include <string>
#include <stack>
class Foo {
public:
Foo() {
std::cout << "created\n";
}
~Foo() {
std::cout << "destroyed " << value << "\n";
}
Foo(const Foo& other) : value(other.value) {
std::cout << "copied\n";
}
Foo(Foo&& other) : value(other.value) {
other.value++;
std::cout << "moved\n";
}
Foo(const Foo&& other) : value(other.value) {
std::cout << "const-moved\n";
}
int value = 0;
};
int main()
{
std::stack<Foo> st;
st.emplace();
const std::stack<Foo>& cst = st;
auto popped = std::move(cst.top());
st.pop();
}
Если вы запустите вышеизложенное, будет использована версия с перемещением const. Однако, реализовав конструктор const-move, вы поймете, что на самом деле вы не можете добиться большего успеха, чем ваш обычный конструктор копирования. Это потому, что other
остаются неизменными. Например, вы не можете получить право собственности на что-либо other
и сбросить его в пределах other
.
И если вы удалите конструктор const-move, компилятор будет использовать обычный конструктор копирования.
Если конструктор копирования удален и предоставляется только конструктор перемещения - , тогда компилятор выдаст вам ошибку.