处理堆芯情况

R44*_*444 1 c++

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

#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;

}
Run Code Online (Sandbox Code Playgroud)

快速解释代码中发生了什么:

请注意,以下行导致seg fault

std::cout << "here: " << i->objinfostack[1]->get_size() << '\n';
Run Code Online (Sandbox Code Playgroud)

发生这种情况是由于无效的访问:

i->objinfostack[1]
Run Code Online (Sandbox Code Playgroud)

因为我将在Blocks列表中得到以下内容:

i->objinfostack[2], i->objinfostack[1]
Run Code Online (Sandbox Code Playgroud)

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

Pau*_*zie 5

我该如何处理这种无效条件

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';
Run Code Online (Sandbox Code Playgroud)

如果您真的想在键不存在的情况下插入项目,并且希望对象指向有效的位置,则需要显式调用insert()

i->objinfostack.insert({1, new ObjInfo(4)});
Run Code Online (Sandbox Code Playgroud)

将会发生的事情是,insert始终检查键项是否存在,如果不存在,则将新项插入到映射中。因此,以上代码将始终创建一个条目(如果该条目不存在),并将保留该条目(如果已存在)。

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

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

2)检测到未发生插入,因此delete单独分配了对象。

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

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

因此,请选择-

1)如果该条目不存在,则不执行任何操作(使用find())或

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


operator []除非您确定要自动使用默认的构造值或零初始化值创建新键,否则永远不要无条件使用地图。