Добавление указателей на вектор в цикле

#c

#c

Вопрос:

Я немного смущен следующим кодом

 void foo() {

  std::list<A*> list;

  for (int i = 0; i < 3; i   ) {
    A a = A(i);
    list.push_back(amp;a);
  }

  for (Iterator it = list.begin(); it != list.end(); it  ) {
     std::cout <<  (*it);
  }
}
 

который трижды выводит объект a с аргументом конструктора 2, то есть последний объект, созданный в цикле.

Что я здесь делаю не так?

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

1. Это не то, как вы включаетесь в список. Даже если бы это было так — вы отправляете ссылки на объекты, которые не будут существовать вне первой итерации цикла

2. @Leeor извините, это была опечатка

3. Вторая часть все еще применяется — вы запускаете один и тот же объект с каждой итерацией, так что у вас есть хороший шанс увидеть последнее значение (и что 3 указателя будут одинаковыми), но не доверяйте неопределенному поведению

4. @Leeor исходя из java, я всегда попадаю в эту ловушку

Ответ №1:

У вас есть список висячих указателей.

  for (int i = 0; i < 3; i   ) {
    A a = A(i);
    list(amp;a);
  }
 

На каждой итерации этот цикл создает объект типа A , который немедленно уничтожается по завершении итерации. Таким образом, содержимое списка не определено. Вам понадобится что-то вроде этого:

  for (int i = 0; i < 3; i   ) {
    A* a = new A(i);
    list(a);
  }
 

…но не забудьте удалить их все в другом цикле, когда закончите со списком.

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

1. Или используйте std::shared_ptr<A> или std::unique_ptr<A> вместо необработанного указателя.

Ответ №2:

Переменная a является локальной для первого цикла for , поэтому она уничтожается в конце каждой итерации цикла. Это означает, что после завершения цикла все три указателя list указывают на объекты, которые больше не существуют. Разыменование этих указателей приводит к неопределенному поведению.

Ответ №3:

Если вы хотите меньше беспокоиться о том, чтобы не забывать выделять выделенную память (и иметь более приятный код, менее подверженный ошибкам), вам следует использовать unique_ptr or shared_ptr (прочитайте о них и выберите тот, который лучше всего соответствует вашим потребностям).

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

 cout<<"Scope begins"<<endl;
{
    vector< unique_ptr<A> > v;
    for (int i=0; i<5;   i){
        v.push_back(unique_ptr<A>(new A(i)) );
    }
}
cout<<"Scope ends"<<endl;
 

Живая демонстрация здесь.