странное поведение с stl-контейнерами и указателями - PullRequest
2 голосов
/ 25 мая 2011

Я не понимаю, почему не работает следующее:

queue<int*> q;

int counter = 1;
for (int i = 0; i < 3; i++) {
    int a[1] = {counter};
    q.push(a);
    counter++;
}

while (!q.empty()) {
    int *top = q.front();
    q.pop();

    cout << top[0] << endl;
}

Должно быть распечатано: 1 2 3, но вместо этого распечатано 3 3 3.Это связано с тем, что указатели в очереди все одинаковы после каждого цикла.Почему это происходит?

Ответы [ 4 ]

8 голосов
/ 25 мая 2011

Вы храните указатели на локальные переменные и используете эти указатели после того, как локальные переменные, на которые они указывают, вышли из области видимости.

Другими словами: вы вызываете Неопределенное поведение .

Результат: он не должен распечатывать «1 2 3».Он не должен ничего делать, и ему разрешено делать все, что угодно.«3 3 3» мне кажется разумным, так как также допускается падение.

4 голосов
/ 25 мая 2011
int a[1] = {counter};
q.push(a);

Не правильно. Он вызывает неопределенный behvaiour, так как a не существует вне фигурных скобок (блок for-loop). Даже если он был четко определен, у вашего кода есть другая проблема, все элементы в queue одинаковы, так как a (одна и та же память) многократно используется в цикле.

Решение таково:

int *a = new int[1];
a[0] = counter;
q.push(a);

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


Но мне интересно, если каждый элемент в queue является только одним int, то почему бы не использовать следующее:

queue<int> q;

for (int i = 0; i < 3; i++) 
{
  q.push(counter);
  counter++;
}

Или, если вы действительно хотите массив, то почему бы не использовать std::queue<std::vector<int> > как:

std::queue<std::vector<int> > q;

for (int i = 0; i < 3; i++) 
{
  std::vector<int> v;
  v.push_back(counter);
  q.push(v); //dont worry - a copy of the vector is being pushed!
  counter++;
}

Таким образом, вам не нужно иметь дело с необработанными указателями. Вам не нужно выделять или освобождать память самостоятельно, что, на мой взгляд, является безопасным подходом!

3 голосов
/ 25 мая 2011

У вас неопределенное поведение, так как ваше объявление a выходит из области видимости в конце цикла, когда вы помещаете его в очередь.

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

1 голос
/ 25 мая 2011

Если вы настаиваете на использовании указателей на целые числа, следующий код делает то, что вы хотите:

#include <queue>
#include <iostream>

int main()
{
  std::queue<int*> q;

  int counter = 1;
  for (int i = 0; i < 3; i++) {
    int* a = new int;
    *a = counter;
    q.push(a);
    counter++;
  }

  while (!q.empty()) {
    int *top = q.front();
    q.pop();

    std::cout << *top << std::endl;
    delete top;
  }

  return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...