我有一些简单的代码(这是我拥有的较大代码的一个较小的示例):
#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)
我的问题是如何处理这种无效条件。
我该如何处理这种无效条件
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 []除非您确定要自动使用默认的构造值或零初始化值创建新键,否则永远不要无条件使用地图。
| 归档时间: |
|
| 查看次数: |
73 次 |
| 最近记录: |