C++: является ли push back (new Object ()) утечкой памяти?

следующий код C++ утечка памяти?

list.push_back(new String("hi"));

Как я понимаю, push_back из любой коллекции/контейнера std всегда делает копию. Итак, если новая строка скопирована, ничто не может удалить новую строку правильно? поскольку после push_back нет ссылки на него...

Я прав или ошибаюсь здесь?

спасибо.

Jbu

edit: я думаю, что ошибаюсь, так как new вернет указатель...у нас всегда будет указатель, чтобы иметь возможность удалить новую строку

7 ответов


нет, вектор хранит указатели и копия указателя. Вы можете удалить объект в любое время.

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


да, но не по той причине, вы думаете.

в зависимости от того, как list определяется и инициализируется,push_back может бросить исключение. Если это так, указатель возвращается из new теряется, и никогда не смогут освободиться.

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


если бы я увидел этот код, я был бы очень подозрителен, что возможна утечка памяти. На поверхности кажется, что он добавляет выделенный String* на list<String*>. По моему опыту, это часто сопровождается плохим кодом обработки ошибок, который неправильно освобождает выделенную память.

а это опасно во многих случаях это не обязательно утечка памяти. Рассмотрим следующий пример:

class Container {
  ~Container() {
    std::list<String*>::iterator it = list.begin();
    while (it != list.end()) {
      delete *it;
      it++;
    }
  }

  void SomeMethod() {
    ...
    list.push_back(new String("hi"));
  }

  std::list<String*> list;
}

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

редактировать

как отметил ашеплер, все еще есть утечка, если push_back метод бросает исключение.


вы правы, при условии, что ничто не удаляет строку, когда она удаляется из списка.


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

и лучший способ сделать это-использовать смарт-указатель. Например, shared_ptr Boost или shared_ptr C++0x.


list.push_back(new String("hi"));

Почему вы выделяете динамические строки в первую очередь? Если вы не хотите общаться между различными частями вашей программы, изменяя строки (что было бы довольно необычно), избавьтесь от указателя:

std::list<std::string> list;         // note: no pointer!
list.push_back(std::string("hi"));   // explicitly create temporary
list.push_back("hi");                // alternative: rely on coercion

нет.

Вы можете удалить объект, выполнив:

delete list[i];
list.erase(list.begin() + i);

или очистить весь список по:

for (unsigned int i = 0; i < list.size(); ++i)
{
  delete list[i];
}
list.clear();