std::deque, ссылки и «поп»

#c #reference #queue #deque

Вопрос:

Я нашел здесь следующий код:

 template <typename T>
//some code here

std::queue<T> search_queue; 
std::unordered_set<T> searched;

while (!search_queue.empty()) {
  Tamp; person = search_queue.front(); // 'Tamp; person' is what I'm particularly interested about.
  search_queue.pop();

  // some code here

  if (searched.find(person) == searched.end()) {
    // some code here
  }
}
 

Поскольку std::очередь действует как оболочка базового контейнера, которым в нашем случае является std::deque, мы находим следующее о pop_front std::deque:

Итераторы и ссылки на удаленный элемент становятся недействительными.

Следовательно, Tamp; p должно быть ошибкой, потому что элемент, на который он ссылается, стирается сразу после создания ссылки.

Так ли это?

Спасибо.

Комментарии:

1. Ваши рассуждения верны, а код-нет.

2. То, что ваш связанный код когда-либо работал, связано только с неопределенным поведением, которое, возможно (и ненадежно), является тем поведением, которое вы хотели.

3. чтобы исправить это, сделайте так, чтобы человек не был ссылкой

4. Или исправить это, pop() только после того, как вы закончите доступ Tamp; person

Ответ №1:

 Tamp; person = search_queue.front(); // 'Tamp; person' is what I'm particularly interested about.
search_queue.pop();
 

да, после search_queue.pop() этого ссылка Tamp; person больше не действительна.

 if (searched.find(person) == searched.end()) {
 

и это (и, возможно, другой код) становится неопределенным поведением.

Возможным решением является

 for (;!search_queue.empty(); search_queue.pop()) {
  Tamp; person = search_queue.front(); // 'Tamp; person' is what I'm particularly interested about.


  if (searched.find(person) == searched.end()) {
    // some code here
  }
}
 

который отличается только тем, что мы этого не pop делаем, пока не выйдем из цикла без break ing, и search_queue не выскакивает, пока мы не повторим.

Альтернативой является

 while (!search_queue.empty()) {
  T person = std::move(search_queue.front());
  search_queue.pop();


  if (searched.find(person) == searched.end()) {
    // some code here
  }
}
 

где мы перемещаем передний элемент в локальную переменную.