Valgrind сумасшедший или это настоящая утечка памяти в итераторе карты std? - PullRequest
5 голосов
/ 20 мая 2010

Ну, я очень новичок в Valgrind и в профайлах утечки памяти в целом.И я должен сказать, что это немного страшно, когда вы начинаете использовать их, потому что вы не можете перестать задаваться вопросом, сколько утечек вы могли оставить нерешенными раньше!

Кстати, поскольку я не опытный в c ++Программист, я хотел бы проверить, не является ли это утечкой памяти или что Valgrind делает ложное срабатывание?

typedef std::vector<int> Vector;
typedef std::vector<Vector> VectorVector;
typedef std::map<std::string, Vector*> MapVector;
typedef std::pair<std::string, Vector*> PairVector;
typedef std::map<std::string, Vector*>::iterator IteratorVector;

VectorVector vv;
MapVector m1;
MapVector m2;

vv.push_back(Vector());
m1.insert(PairVector("one", &vv.back()));

vv.push_back(Vector());
m2.insert(PairVector("two", &vv.back()));

IteratorVector i = m1.find("one");
i->second->push_back(10);
m2.insert(PairVector("one", i->second));

m2.clear();
m1.clear();
vv.clear();

Почему это так?Разве команда clear не должна вызывать деструктор каждого объекта и каждого вектора?

Теперь, выполнив несколько тестов, я нашел различные решения для утечки:

1) Удаление:

i->second->push_back(10);

2) Добавление:

delete i->second;

3) Удаление второго

vv.push_back(Vector());
m2.insert(PairVector("two", &vv.back()));

Использование решения 2) делает печать Valgring: 10 выделяет, 11 освобождает Это нормально?

Поскольку я не использую новый, почему я должен удалить?

Спасибо, за любую помощь!

Ответы [ 3 ]

2 голосов
/ 20 мая 2010

В основном эта строка вызывает проблему:

i->second->push_back(10);

Это потому что я-> секунда, возможно, стала недействительной, когда вы сделали:

vv.push_back(Vector());

Второй раз.

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

Если вы хотите сохранить общее решение, создайте список векторов для вашего объекта vv. Тогда вставка в список не повлияет на уже существующих участников, и ваши карты будут работать правильно.

std::list<Vector> vv;  // insertion into this will not invalidate any other members.
                       // Thus any pointers to members you have will not become invalidated.

Лично я думаю, что вы слишком усложняете вещи.
Я думаю, что вы можете достичь тех же результатов, значительно упростив это.
Если на векторы не ссылаются несколько элементов карты, просто поместите вектор на карту.

std::map<std::string, std::vector<int> >    m1;

m1["one"].push_back(10);
m1["two"].push_back(20);
1 голос
/ 20 мая 2010

У вас здесь неопределенное поведение:

m1.insert(PairVector("one", &vv.back()));

vv.push_back(Vector());

Вставка делает недействительными итераторы и ссылки, указывающие на вектор, что также означает, что указатель, сохраненный на карте, в основном указывает на некоторую черную дыру после вставки.

делает печать Valgring: 10 ассигнований, 11 освобождений Это нормально?

Странно, а также не печатается ли что-то о двойных освобождениях?

Для решения я бы предложил использовать контейнер, отличный от vector (например, list или deque, чьи мутирующие функции делают недействительными итераторы, но не ссылки). Или вы можете хранить указатели (желательно умные, но обычные) на данные в векторе, чтобы адрес реальных данных был стабильным.

0 голосов
/ 20 мая 2010

Вы делаете некоторые опасные вещи с векторами здесь. Вы сохраняете указатели на векторы, которые могут стать недействительными во время выполнения программы.

std::vector<>::push_back() может сделать недействительными любые итераторы или ссылки на std::vector<>, если он уже был заполнен. Поскольку std::vector<> гарантирует, что его содержимое будет храниться непрерывно (так что вы можете использовать его вместо массива), когда ему требуется больше памяти, ему приходится копировать себя в другой блок памяти, и оригинал становится недействительным.

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

...