Valgrind:无效读取大小 8 错误
Valgrind: Invalid read of size 8 error
当我 运行 通过 valgrind
我的程序时,我得到以下信息
==29852== Invalid read of size 8
==29852== at 0x4EDEA50: std::_Rb_tree_increment(std::_Rb_tree_node_base const*) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==29852== by 0x414EEA: std::_Rb_tree_const_iterator<std::pair... >::operator++() (stl_tree.h:284)
==29852== by 0x4268CF: Tree::removeConstantsPair(std::set...) (Tree.h:65)
==29852== by 0x4239C4: yy_reduce(yyParser*, int) (parser.y:251)
==29852== by 0x425F6D: Parse(void*, int, Token*, Tree*) (parser.c:1418)
==29852== by 0x404837: main (main.cpp:95)
Tree.h 中的第 65 行是
inline void removeConstantsPair(set<pair<string, string>>& vec){
set<string>::iterator itr;
for(auto &v : vec){ //This is line 65
itr = domainList.find(v.first);
if(itr != domainList.end())
vec.erase(v);
}
}
但是泄漏摘要说没有丢失的记忆。
据我了解,如果我从已释放的内存中读取,则会发生无效读取,因此在我的情况下 &vec
之前必须已被释放。我的程序 运行 并没有崩溃。
谁能解释一下为什么会出现内存读取错误。
"invalid memory read" 也可能由于许多其他原因而发生,而不是问题中所述的原因。
一个例子:
通过 new
分配内存的请求通常分配的内存比新 class 实例所需的内存多一点。例如,特定的 C++ 实现可能会以 16 字节的倍数分配内存。因此,对于 class 的 sizeof
实例 return 12 的 new
实际上最终会分配 16 个字节,并尝试读取实际实例化的末尾对象最终将被 valgrind 正确标记为无效内存读取。
问题很可能是由线路引起的:
vec.erase(v);
使用范围 for 循环并从容器中删除项目不是一个好主意。将循环更改为:
for ( auto iter = vec.begin(); iter != vec.end(); /* Empty on purpose*/ )
{
if(domainList.find(iter->first) != domainList.end())
{
iter = vec.erase(iter);
}
else
{
++iter;
}
}
以下小程序显示在Visual Studio编译器下运行时的错误:
#include <string>
#include <set>
#include <map>
std::set<std::string> domainList = {"abc", "123", "456"};
using namespace std;
void removeConstantsPair(set<pair<string, string>>& vec)
{
set<string>::iterator itr;
for(auto &v : vec)
{
itr = domainList.find(v.first);
if(itr != domainList.end())
vec.erase(v); // <--erasing this iterator makes it invalid
}
}
int main()
{
std::set<std::pair<string, string>> vec = {make_pair("abc", "xyz"),
make_pair("456", "xyz"),
make_pair("000", "xyz")};
removeConstantsPair(vec);
}
当尝试在 for
循环中擦除的迭代器上递增时,Visual Studio 调试 运行time 使用 "Expression map/set iterator not incrementable" 断言。
因此解决方案是确保将要递增的迭代器不是被擦除的迭代器。
void removeConstantsPair(set<pair<string, string>>& vec)
{
set<string>::iterator itr;
auto iterSet = vec.begin();
while (iterSet != vec.end())
{
itr = domainList.find((*iterSet).first);
if (itr != domainList.end())
{
auto erasedIter = iterSet;
++iterSet;
vec.erase(erasedIter);
}
else
++iterSet;
}
}
当我 运行 通过 valgrind
我的程序时,我得到以下信息==29852== Invalid read of size 8
==29852== at 0x4EDEA50: std::_Rb_tree_increment(std::_Rb_tree_node_base const*) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==29852== by 0x414EEA: std::_Rb_tree_const_iterator<std::pair... >::operator++() (stl_tree.h:284)
==29852== by 0x4268CF: Tree::removeConstantsPair(std::set...) (Tree.h:65)
==29852== by 0x4239C4: yy_reduce(yyParser*, int) (parser.y:251)
==29852== by 0x425F6D: Parse(void*, int, Token*, Tree*) (parser.c:1418)
==29852== by 0x404837: main (main.cpp:95)
Tree.h 中的第 65 行是
inline void removeConstantsPair(set<pair<string, string>>& vec){
set<string>::iterator itr;
for(auto &v : vec){ //This is line 65
itr = domainList.find(v.first);
if(itr != domainList.end())
vec.erase(v);
}
}
但是泄漏摘要说没有丢失的记忆。
据我了解,如果我从已释放的内存中读取,则会发生无效读取,因此在我的情况下 &vec
之前必须已被释放。我的程序 运行 并没有崩溃。
谁能解释一下为什么会出现内存读取错误。
"invalid memory read" 也可能由于许多其他原因而发生,而不是问题中所述的原因。
一个例子:
通过 new
分配内存的请求通常分配的内存比新 class 实例所需的内存多一点。例如,特定的 C++ 实现可能会以 16 字节的倍数分配内存。因此,对于 class 的 sizeof
实例 return 12 的 new
实际上最终会分配 16 个字节,并尝试读取实际实例化的末尾对象最终将被 valgrind 正确标记为无效内存读取。
问题很可能是由线路引起的:
vec.erase(v);
使用范围 for 循环并从容器中删除项目不是一个好主意。将循环更改为:
for ( auto iter = vec.begin(); iter != vec.end(); /* Empty on purpose*/ )
{
if(domainList.find(iter->first) != domainList.end())
{
iter = vec.erase(iter);
}
else
{
++iter;
}
}
以下小程序显示在Visual Studio编译器下运行时的错误:
#include <string>
#include <set>
#include <map>
std::set<std::string> domainList = {"abc", "123", "456"};
using namespace std;
void removeConstantsPair(set<pair<string, string>>& vec)
{
set<string>::iterator itr;
for(auto &v : vec)
{
itr = domainList.find(v.first);
if(itr != domainList.end())
vec.erase(v); // <--erasing this iterator makes it invalid
}
}
int main()
{
std::set<std::pair<string, string>> vec = {make_pair("abc", "xyz"),
make_pair("456", "xyz"),
make_pair("000", "xyz")};
removeConstantsPair(vec);
}
当尝试在 for
循环中擦除的迭代器上递增时,Visual Studio 调试 运行time 使用 "Expression map/set iterator not incrementable" 断言。
因此解决方案是确保将要递增的迭代器不是被擦除的迭代器。
void removeConstantsPair(set<pair<string, string>>& vec)
{
set<string>::iterator itr;
auto iterSet = vec.begin();
while (iterSet != vec.end())
{
itr = domainList.find((*iterSet).first);
if (itr != domainList.end())
{
auto erasedIter = iterSet;
++iterSet;
vec.erase(erasedIter);
}
else
++iterSet;
}
}