处理核心转储条件

Handling core dump condition

本文关键字:条件 转储 核心 处理      更新时间:2023-10-16

我有一些简单的代码(这是我拥有的较大代码的较小示例(:

#include <iostream>
#include <unordered_map>
#include <list>
// List of blocks
std::list<struct Block> Blocks;
class ObjInfo
{
private:
  int size;
public:
  ObjInfo(int size){this->size = size;}
  int get_size() {return size;}
};
struct Block
{
  // name of the block
  int x;
  // Actual variable stack
  std::unordered_map <int, ObjInfo*> objinfostack;
};
int main()
{
int x = 2;
while( x >= 0 )
{
  Block b;
  b.x = x;
  b.objinfostack.insert(std::make_pair(x, new ObjInfo(4)));
  --x;
  Blocks.push_front(b);
}
for(std::list<struct Block>::iterator i = Blocks.begin(); i!=Blocks.end(); ++i)
{
  std::cout << "here: " << i->objinfostack[1]->get_size() << 'n';
}
return 0;
}

关于代码中发生的事情的快速说明:

注意以下行导致seg fault

std::cout << "here: " << i->objinfostack[1]->get_size() << 'n';

由于无效访问而发生的发生:

i->objinfostack[1]

我将在Blocks列表中得到类似的东西:

i->objinfostack[2], i->objinfostack[1]

我的问题是如何处理这种无效的条件。

如何处理这种无效条件

如果您不确定该条目是否存在,则不使用operator []来处理此类条件。如果不存在密钥值,则operator []将自动将条目插入地图。您无法更改此行为 - 当密钥不存在时,operator []的工作方式就是为该值创建nullptr,因为这是指针类型的零键值。

相反,您应该使用std::unordered_map::find()测试键是否存在而不是使用[],并使用返回的迭代器(如果不是end()(:

auto iter = i->objinfostack.find(1);
if ( iter != i->objinfostack.end())
    std::cout << "here: " << iter->second->get_size() << 'n';

如果您真的想插入一个项目,如果密钥不存在,并且您希望对象指向某个地方,则需要明确调用insert()

i->objinfostack.insert({1, new ObjInfo(4)});

将会发生的是,插入始终检查以查看密钥条目是否存在,如果不存在,则将插入新的条目。因此,如果不存在,则上述代码将始终创建一个条目,如果条目已经存在,则将不存在任何条目。

然而,一个问题是,如果对象已经存在,则会发生内存泄漏,因为new将在没有相应删除的情况下调用CC_11。要解决这个问题,您可以

1(将地图更改为将RAII类型存储为值类型(例如std::vector<ObjInfo> std::shared_ptr,STD :: unique_ptr`(或

2(检测未发生插入,因此分别分配的对象分别。

auto new_ptr = new ObjInfo(4);
auto pr = i->objinfostack.insert({1, new_ptr});
if (!pr.second) // insert didn't happen
    delete new_ptr;

但是,当然这很麻烦,可能要做的最简单的事情是首先使用std::map::find(),如果找不到条目,则将/插入地图中分配/插入。

所以请您选择 -

1(如果条目不存在,则什么都不做(使用find(((或

2(如果条目不存在,请创建一个具有有效ObjInfo的条目(使用insert(),但请注意上面表达的警告(。


底线永远不会使用地图operator []无条件地使用,除非您确定要自动创建一个具有默认构造或零定位值的新键。

索引无效,因此崩溃:

i->objinfostack[1]

将第一个块添加到列表中,将在地图中添加一个条目:

objinfostack[2] = {2, somePointer}

将添加第二个块:

objinfostack[1] = {1, somePointer}

因此,当您沿着列表走时,您最终将在仅插入索引[2]的块上访问索引[1]。结果,块将无效。如果您做了这样的事情,问题将消失:

for(std::list<Block>::iterator i = Blocks.begin(); i!=Blocks.end(); ++i)
{
  std::cout << "Block....n";
  for(auto& val : i->objinfostack)
  {
    std::cout << '[' << val.first << "] " << val.second->get_size() << 'n';
  }
}