Скопируйте std :: stack в std :: vector - PullRequest
12 голосов
/ 03 декабря 2010

Гарантируется ли следующий код стандартом для работы (при условии, что st не пустой)?

#include <vector>
#include <stack>
int main()
{
   extern std::stack<int, std::vector<int> > st;
   int* end   = &st.top() + 1;
   int* begin = end - st.size();
   std::vector<int> stack_contents(begin, end);
}

Ответы [ 6 ]

9 голосов
/ 03 декабря 2010

Да.

std::stack - это просто контейнерный адаптер.

Вы можете видеть, что .top() на самом деле (§23.3.5.3.1)

reference top() { return c.back(); }

Где c - контейнер, который в данном случае является std::vector

Это означает, что ваш код в основном переведен на:

   extern std::vector<int> st;
   int* end   = &st.back() + 1;
   int* begin = end - st.size();
   std::vector<int> stack_contents(begin, end);

И поскольку std::vector гарантированно будет непрерывным, проблем не должно быть.

Однако это не значит, что это хорошая идея. Если вам нужно использовать такие «хаки», как правило, это показатель плохого дизайна. Вы, вероятно, хотите использовать std::vector с самого начала.

5 голосов
/ 03 декабря 2010

Только std::vector гарантирует, что C ++ 03 будет иметь смежные элементы ( 23.4.1 ).В C ++ 1x это также будет расширено до std::string ( дефект # 530 ).

2 голосов
/ 03 декабря 2010

Да, это гарантировано. Векторы гарантированно используют непрерывное хранилище, поэтому ваш код будет работать. Хотя это немного глупо - и если кто-то изменит базовый тип контейнера стека, ваш код продолжит компиляцию без ошибок, но поведение во время выполнения будет нарушено.

1 голос
/ 03 декабря 2010

Согласно этой странице , std::stack использует класс контейнера для хранения элементов.

Полагаю, то, что вы предлагаете, работает, только если контейнер хранит свои элементы линейным образом (std::vector).

По умолчанию std::stack использует std::deque, который, насколько я знаю, не соответствует этому требованию. Но если вы укажете std::vector в качестве класса контейнера, я не вижу причины, по которой он не будет работать.

1 голос
/ 03 декабря 2010

К сожалению, у меня нет ссылки на стандарт, чтобы подтвердить это, но я не думаю, что это может привести к ошибкам:

  • Указание std::vector<int> в качествеТип контейнера означает, что элементы должны храниться в std::vector<int>.
  • st.top() и должны возвращать ссылку на элемент в базовом контейнере (то есть элемент в std::vector<int>.Контейнер в том, что он поддерживает back(), push_back() и pop_back(), мы можем разумно предположить, что top() возвращает ссылку на последний элемент в векторе.
  • end, следовательно, указывает на одно прошлоепоследний элемент.
  • start, следовательно, указывает на начало.

Заключение: Если предположение не верно, оно должно работать.ссылка другого ответа на стандарт, предположение верно, поэтому он работает.

0 голосов
/ 03 декабря 2010

Редактировать: исходный оператор отредактирован, стандарт фактически предоставляет полное определение стекового адаптера, ничего не оставляя разработчикам.см. верхний ответ.

Вам нужен контейнер, который имеет метод push и pop и позволяет проверять элементы в любом месте контейнера и использует std::vector для хранения.В стандартной библиотеке шаблонов есть такой контейнер

, он называется std::vector.

Использовать std::stack только для неволи

...