Удаляет ли std::vector.clear () (свободную память) каждый элемент?

Рассмотрим этот код:

#include <vector>

void Example()
{
    std::vector<TCHAR*> list;
    TCHAR* pLine = new TCHAR[20];
    list.push_back(pLine);
    list.clear();    // is delete called here?
    // is delete pLine; necessary?
}

Есть ли list.clear() звонить delete по каждому элементу? Т.е. нужно ли освобождать память до / после list.clear()?

Ответов (6)

Решение

Нет (вам нужно выполнить удаление самостоятельно в конце, как вы предлагаете в своем примере, поскольку уничтожение лысого указателя ничего не делает). Но вы можете использовать интеллектуальный указатель на ускорение [или другую идиому на основе RAII], чтобы заставить его делать то, что нужно ( auto_ptr не будет работать правильно в контейнере, поскольку он ведет себя несовместимо при копировании и т. Д.), Но убедитесь, что вы понимаете подводные камни такие умные указатели перед использованием. (Как упоминает Бенуа, в данном случае basic_string это именно то, что вы действительно ищете.)

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

РЕДАКТИРОВАТЬ: Существенно переработано, чтобы охватить элементы, которые Бенуа привнес в свой гораздо более подробный ответ, благодаря сильному подталкиванию Эрвикера и Джеймса Матта - спасибо, что подтолкнули меня к должной осмотрительности по этому поводу!

Неа. Этого не происходит, поскольку нет гарантии, что вы не используете указатель где-либо еще. Если бы это не была переменная-указатель, она бы освободила их (вызвав деструктор)

std::vector вызывает деструктор каждого содержащегося в нем элемента при clear() вызове. В вашем конкретном случае он уничтожает указатель, но объекты остаются.

Умные указатели - это правильный путь, но будьте осторожны. auto_ptr не может использоваться в контейнерах std. boost::scoped_ptr тоже не могу. boost::shared_ptr может, но в вашем случае это не сработает, потому что у вас нет указателя на объект, вы фактически используете массив. Итак, решение вашей проблемы - использовать boost::shared_array.

Но я предлагаю вам использовать std::basic_string<TCHAR> вместо этого, где вам не придется иметь дело с управлением памятью, но при этом получить преимущества работы со строкой.

Вот один из способов узнать, что это не так - попробуйте его на не полностью определенном классе:

#include <vector>
class NotDefined;

void clearVector( std::vector<NotDefined*>& clearme )
{
    clearme.clear();    // is delete called here?
}

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

Вы также можете использовать библиотеку контейнеров Boost Pointer . Здесь особо не рекомендуется (опять же, потому что вы используете массивы вместо отдельных объектов, хотя об std::string этом позаботитесь), но это полезная и малоизвестная библиотека, которая решает проблему, указанную в заголовке.

Вы можете просто написать простую функцию-шаблон, которая сделает это за вас:

template <class T>
void deleteInVector(vector<T*>* deleteme) {
    while(!deleteme->empty()) {
        delete deleteme->back();
        deleteme->pop_back();
    }

    delete deleteme;
}

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