std :: vector разрушение и неожиданная утечка памяти - PullRequest
2 голосов
/ 10 июля 2011

Рассмотрим следующий пример:

#include <vector>
class Foo {
    std::vector<int*> v;
public:
    Foo() {
        this->v.push_back(new int(23));
        this->v.push_back(new int(24));
        this->v.push_back(new int(25));
    }

    ~Foo() {
    }
};

int main() {
    Foo f;
    return 0;
}

Когда f выходит из области видимости в main (), вызывается деструктор f, который должен косвенно освобождать fv. Согласно this , деструкторкаждого элемента вектора v теперь нужно вызывать.

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

$ valgrind --leak-check=full ./a.out

Чтоя здесь скучаю?

Ответы [ 4 ]

10 голосов
/ 10 июля 2011

std::vector<T> действительно вызывает деструктор T, когда он уничтожен.Здесь T равно int *.Деструктор int * ничего не делает.Память для int * сама по себе освобождается, но int s, на которые они указывают, не являются.

Обратите внимание:

int main() {
   int *x = new int(23);
   return 0;
}

Это демонстрирует ту же проблему;когда x выходит из области видимости, его деструктор действительно вызывается, и хранилище для указателя , который является x, освобождается, но, поскольку деструктор указателя является неоперативным, указывает на int не освобожден.

Более того, vector не знает, как были выделены int s.Они могут быть выделены на new int, но они также могут указывать на элементы внутри массива, выделенного с new int[200], или они могут указывать на данные malloc d, или они могут указывать на буфер mmap ',или они могут указывать на элементы структуры, или два вектора могут указывать на одни и те же int s ... и т. д. vector недостаточно умен, чтобы предугадать, что вы хотите сделать с ними, и поэтому он оставляет их в покое (Кроме того, если предоставить vector логику для удаления указанных элементов, это приведет к разрыву векторов не указательных элементов, таких как std::vector<int>, так как вы не можете delete и int!)

.либо используйте std::vector<int>, либо используйте умный указатель вместе с ним, например std::vector<boost::shared_ptr<int> >.Обратите внимание, что использование умных указателей может увеличить накладные расходы;с C ++ 0x вы сможете использовать std::vector<std::unique_ptr<int>> в сочетании с std::move, чтобы избежать этих издержек.Boost также имеет вектор-указателей , которые освобождают элементы, на которые указывают, как вы и ожидали.

4 голосов
/ 10 июля 2011

Деструктор каждого элемента вектора v теперь должен называться

Да: int* объекты, хранящиеся в векторе, уничтожаются (что фактически неоп).Объекты, на которые указывают указатели в контейнере, не уничтожаются.

Рассмотрим следующую, одинаково действительную программу:

{
    int x;
    std::vector<int*> v;
    v.push_back(&x);
}   // x cannot be delete'd because it isn't dynamically allocated.

Вы должны использовать умный указатель, например std::unique_ptr или shared_ptr, чтобы вам не приходилось беспокоиться о памятиуправление (не используйте std::auto_ptr; оно несовместимо с контейнерами стандартной библиотеки, поскольку на самом деле его нельзя копировать).Если вы не используете умный указатель, тогда вам нужно уничтожить динамически объекты самостоятельно;сделать это правильно довольно сложно.

2 голосов
/ 10 июля 2011

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

«Деструктор» для типа указателя должен просто удалить этот указатель. Он не касается данных, которые расположены по адресу памяти, сохраненному указателем. Рассмотрим следующий пример:

int a = 5;
int* i = &a;
if (true)
{
   int* j = i;
} //j goes out of scope, should *i and a be deleted? no.

Так что вам нужно будет сделать это в деструкторе:

std::vector<int*>::iterator iter;
for (iter = v.begin(); iter != v.end(); iter++)
{
   delete *iter;
}
2 голосов
/ 10 июля 2011

Каждый элемент вашего вектора является int *.Когда int * уничтожается, язык автоматически не вызывает delete для него.Другими словами, уничтожается указатель, а не указатель.

...