c – stl map operator []不好

前端之家收集整理的这篇文章主要介绍了c – stl map operator []不好前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我的代码审阅者已经指出,使用地图的operator []是非常糟糕的,导致错误
map[i] = new someClass;    // potential dangling pointer when executed twice

要么

if (map[i]==NULL) ...      // implicitly create the entry i in the map

虽然我在阅读API后看到insert()更好的风险,因为它检查重复,因此可以避免悬挂指针发生,我不明白如果处理正确,为什么[]不能用于所有?

我选择地图作为我的内部容器,正是因为我想使用其快速和自我解释的索引功能.

我希望有人可以和我争辩更多,或站在我身边:)

解决方法

当你想要设置一个键的值(如果已经有一个值覆盖它),那么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.

否则有几种方法可以根据上下文来做,但是我建议总是使用一般的解决方案(这样你就不能错了).

找到一个值并创建它,如果它不存在:

一般解决方案(推荐,因为它一直有效)

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

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

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

注意:您可以轻松地将一般解决方案包含在帮助程序中:

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

注意,我传递一个模板化的工厂方法,而不是一个创建大小写的值,这样,当找到该值并且不需要创建时,就没有开销.由于lambda作为模板参数传递,编译器可以选择内联它.

猜你在找的C&C++相关文章