Fig*_*igo 13 c++ stl map operators
我的代码审查员已经指出地图的operator []的使用非常糟糕并导致错误:
map[i] = new someClass; // potential dangling pointer when executed twice
Run Code Online (Sandbox Code Playgroud)
要么
if (map[i]==NULL) ... // implicitly create the entry i in the map
Run Code Online (Sandbox Code Playgroud)
虽然我理解读取API之后的风险insert(),因为它检查重复是更好的,因此可以避免悬空指针发生,我不明白,如果处理得当,为什么[]不能使用呢?
我选择map作为我的内部容器,因为我想使用它快速且自我解释的索引功能.
我希望有人可以和我争论更多或站在我身边:)
ron*_*nag 13
唯一一次(我能想到)operator[]可能有用的地方是你想要设置一个键的值(如果它已经有一个值就覆盖它),并且你知道覆盖是安全的(它应该是因为你应该使用智能指针,而不是原始指针)并且默认构造很便宜,并且在某些情况下,值应该具有无抛出构造和赋值.
例如(类似于你的第一个例子)
std::map<int, std::unique_ptr<int>> m;
m[3] = std::unique_ptr<int>(new int(5));
m[3] = std::unique_ptr<int>(new int(3)); // No, it should be 3.
Run Code Online (Sandbox Code Playgroud)
否则有几种方法可以根据上下文进行,但是我建议总是使用通用解决方案(这样你就不会出错).
查找值并创建它(如果它不存在):
1.一般解决方案(推荐它始终有效)
std::map<int, std::unique_ptr<int>> m;
auto it = m.lower_bound(3);
if(it == std::end(m) || m.key_comp()(3, it->first))
it = m.insert(it, std::make_pair(3, std::unique_ptr<int>(new int(3)));
Run Code Online (Sandbox Code Playgroud)
2.具有廉价的违约建设价值
std::map<int, std::unique_ptr<int>> m;
auto& obj = m[3]; // value is default constructed if it doesn't exists.
if(!obj)
{
try
{
obj = std::unique_ptr<int>(new int(3)); // default constructed value is overwritten.
}
catch(...)
{
m.erase(3);
throw;
}
}
Run Code Online (Sandbox Code Playgroud)
3.具有廉价的默认构造和无投入价值
std::map<int, my_objecct> m;
auto& obj = m[3]; // value is default constructed if it doesn't exists.
if(!obj)
obj = my_objecct(3);
Run Code Online (Sandbox Code Playgroud)
注意:您可以轻松地将常规解决方案包装到辅助方法中:
template<typename T, typename F>
typename T::iterator find_or_create(T& m, const typename T::key_type& key, const F& factory)
{
auto it = m.lower_bound(key);
if(it == std::end(m) || m.key_comp()(key, it->first))
it = m.insert(it, std::make_pair(key, factory()));
return it;
}
int main()
{
std::map<int, std::unique_ptr<int>> m;
auto it = find_or_create(m, 3, []
{
return std::unique_ptr<int>(new int(3));
});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
请注意,我传递模板化工厂方法而不是create case的值,这样在找到值时不会产生任何开销,也不需要创建.由于lambda作为模板参数传递,编译器可以选择内联它.
你是对的,map::operator[]必须谨慎使用,但它可能非常有用:如果你想在地图中找到一个元素,如果没有,那就创建它:
someClass *&obj = map[x];
if (!obj)
obj = new someClass;
obj->doThings();
Run Code Online (Sandbox Code Playgroud)
并且地图中只有一个查找.如果new失败,您可能想要从地图中删除NULL指针,当然:
someClass *&obj = map[x];
if (!obj)
try
{
obj = new someClass;
}
catch (...)
{
obj.erase(x);
throw;
}
obj->doThings();
Run Code Online (Sandbox Code Playgroud)
当然,如果你想找到一些东西,但不要插入它:
std::map<int, someClass*>::iterator it = map.find(x); //or ::const_iterator
if (it != map.end())
{
someClass *obj = it->second;
obj->doThings();
}
Run Code Online (Sandbox Code Playgroud)