Подтвердить что ты не робот

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()?

4b9b3361

Ответ 1

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

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

EDIT: Существенно пересмотренный, чтобы охватить элементы Benoit, привел в его гораздо более тщательный ответ, благодаря сильному подталкиванию от Earwicker и James Matta - спасибо, что заставил меня сделать должную осмотрительность на этом!

Ответ 2

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

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

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

Ответ 3

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

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

    delete deleteme;
}

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

Ответ 4

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

#include <vector>
class NotDefined;

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

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

Ответ 5

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

Ответ 6

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