包装地图访问,聪明还是愚蠢?

时间:2013-02-17 08:56:57

标签: c++ templates

我在非性能关键代码中访问了很多地图。我不想一直写通常的find /!= end来检查丢失的密钥。我也不想盲目地使用[]并获得默认值。以下包装函数是智能还是愚蠢?有更简单的方法吗?有没有我不考虑的副作用?

template<typename M>
static typename M::mapped_type getMapValue(const M& m, typename M::key_type key) {

    typename M::const_iterator it = m.find(key);

    if (it != m.end()) {
        return it->second;
    } else {
        std::cerr << "Key: " << key << " not found!" << std::endl;
        std::cerr << "Returning default value." << std::endl;
        return typename M::mapped_type();
    }

}

5 个答案:

答案 0 :(得分:2)

我建议使用std::map::at,然后客户端代码必须决定如何处理使用地图中尚未存在的密钥的调用引发的任何std::out_of_range异常。

std::map<std::string, int> m;

....
int n = m.at("hello!");

答案 1 :(得分:1)

智能

包装std容器通常是一个好主意,因为如果您愿意,可以在将来将它们换掉。

但是,返回默认值的正确行为是什么?它可能在你的情况下,但在大多数情况下,它不会。

答案 2 :(得分:1)

每当STL接口对某些程序逻辑变得麻烦时,我倾向于包装整个容器,而不仅仅是访问单个函数。通常情况下,我会从现有的容器类型私下派生出来,然后重新制作我需要公开的部件。另外,我添加了我需要的实际接口,例如operator []用于类似const地图的对象:

struct mycontainer:
    private map<string, string>
{
    typedef map<string, string> base;
    using base::iterator;
    using base::const_iterator;
    using base::begin;
    using base::end;

    string const& operator[](string const& k) const
    {
        const_iterator it = find(k);
        if(it == end())
            throw runtime_error("lookup failure");
        return it->second;
    }
};

注意:

  • 如果需要特殊的迭代器,Boost中有一个帮助库可以轻松创建自定义迭代器类型。
  • 您还可以显着更改界面,例如返回默认值而不将其添加到地图或返回boost :: optional。后者是IMHO 方式,可以轻松检查存在并一步检索值。

答案 3 :(得分:1)

如果想法是检查,那么你可能想要这样的东西:

if (theMap.count(theKey)) {
  doSomethingWith(theMap[theKey]);
} else {
  doSomethingDefault();
}

名称计数非常笨拙,因为如果元素在那里它只返回true而如果不存在则返回false。我认为它应该与每个键支持多个值的某个容器一致,但之后他们从未编写过该容器。为了重命名“count”“contains”,可能不值得包装地图。

答案 4 :(得分:0)

我认为你最好在找不到元素时抛出异常。无论如何,谁会监控你的程序是否会打印所有这些警告?

另外,考虑使用const-reference来获取密钥,因为std::map会这样做。