5

好吧,总的来说,我对 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 allocs, 11 frees可以吗?

由于我没有使用 new 为什么要删除?

谢谢你的帮助!

4

3 回答 3

2

基本上这条线导致了问题:

i->second->push_back(10);

这是因为当你这样做时 i->second 可能已经变得无效:

vv.push_back(Vector());

第二次。

没有必要打电话清除。当 vv 对象超出范围时,它将正确销毁所有对象。此外,所有地图都不拥有任何向量,因此它们的析构函数不会影响它们指向的向量。因此,您不需要使用 clear。

如果您想保持相同的整体解决方案,请为您的 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);
于 2010-05-20T16:15:08.590 回答
1

您在这里有未定义的行为:

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

vv.push_back(Vector());

插入使指向向量的迭代器和引用无效,这也意味着您存储在映射中的指针在插入后基本上指向某个黑洞。

让 Valgring 打印:10 次分配,11 次释放 可以吗?

很奇怪,它不也打印一些关于双释放的东西吗?

对于解决方案,我建议使用不同的容器vector(例如list,或deque,其变异函数使迭代器无效,但不是引用)。或者您可以在向量中存储指向数据的指针(最好是智能的,但也可以是普通的),以便实际数据的地址是稳定的。

于 2010-05-20T10:25:21.113 回答
0

你在这里用向量做一些危险的事情。您保留了指向在程序执行期间可能变得无效的向量的指针。

std::vector<>::push_back()std::vector<>如果它已满,则可能会使任何迭代器或对 的引用无效。由于std::vector<>保证其内容将连续存储(因此您可以使用它来代替数组),因此当它需要更多内存时,它必须将自己复制到不同的内存块并且原始内存块变得无效。

这意味着push_back()代码中的所有调用(第一个调用除外)都会导致未定义的行为,因此这里可能发生任何事情。

于 2010-05-20T10:35:35.310 回答