Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/138.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;98 std::map::at()的包装器_C++_C++11_Stl - Fatal编程技术网

C++ C++;98 std::map::at()的包装器

C++ C++;98 std::map::at()的包装器,c++,c++11,stl,C++,C++11,Stl,我只能使用C++98,无法访问随C++11添加的std::map::at()的实现 我的目标是编写一个非成员函数at()函数(使用C++98),其行为类似于std::map::at() 因此,我编写了以下非成员函数: template<typename K, typename V> V& at(std::map<K, V> map, K key) { if (map.find(key) == map.end()) throw std::out_of_r

我只能使用C++98,无法访问随C++11添加的
std::map::at()
的实现

我的目标是编写一个非成员函数
at()
函数(使用C++98),其行为类似于
std::map::at()

因此,我编写了以下非成员函数:

template<typename K, typename V>
V& at(std::map<K, V> map, K key)
{
  if (map.find(key) == map.end())
    throw std::out_of_range("key not found");
  return map.find(key)->second;
}
模板
V&at(标准::地图,K键)
{
if(map.find(key)=map.end())
抛出标准::超出范围(“未找到键”);
返回map.find(key)->second;
}
我至少可以看到一个问题,那就是我的版本的行为就像我返回了一个副本一样(见下文)

std::map myMap;
myMap.insert(std::pair(2,43));
//myMap.at(2)=44;//修改引用
//断言(44==myMap.at(2));//好的
at(myMap,2)=44;//不修改地图内的值,为什么?
断言(44==myMap.at(2));//不好
  • 我如何解决这个问题
  • 我的包装器还有其他问题吗

  • 将签名更改为

    V& at(std::map<K, V>& map, K key)
    
    V&at(标准::地图和地图,K键)
    
    主要问题是您正在调用未定义的行为

    您的
    at
    按值获取地图:

    V& at(std::map<K, V> map, K key)
    
    V&at(标准::地图,K键)
    
    因此,您将返回对本地对象中某个项的引用,这是非常未定义的

    您应该使用参考:

    V& at(std::map<K, V>& map, const K& key)
    
    V&at(标准::映射与映射、常数K与键)
    
    您可能还想添加常量版本:

    const V& at(const std::map<K, V>& map, const K& key)
    
    const V&at(const std::map&map,const K&key)
    
    您的方法存在两个问题:

    • 您将映射实例作为值传递,这样不仅可以复制整个映射,还可以返回对该本地副本中某个元素的引用并生成UB
    • 您要查找两次,这在地图上是相当昂贵的操作
    因此,您的代码可以是:

    template<typename K, typename V>
    V& at(std::map<K, V> &map, K key)
    {
       std::map<K,V>::iterator f = map.find(key);
       if ( f == map.end())
         throw std::out_of_range("key not found");
       return f->second;
    }
    
    模板
    V&at(标准::地图和地图,K键)
    {
    std::map::迭代器f=map.find(键);
    如果(f==map.end())
    抛出标准::超出范围(“未找到键”);
    返回f->second;
    }
    
    您应该将
    find
    的结果存储在一个变量中,这样就不会遍历地图两次。这个问题似乎离题了,因为它是关于什么是打字错误。@KubaOber我不同意。问题更多的是,我们不理解为什么按值传递
    映射
    比简单的打字更不能修改元素。OP显然不明白为什么按值传递它不能像他期望的那样工作。假设您的密钥都可以打印,您也可以通过说明找不到哪个密钥来增强错误消息。可能会帮助您在以后抛出此错误时找到错误。
    template<typename K, typename V>
    V& at(std::map<K, V> &map, K key)
    {
       std::map<K,V>::iterator f = map.find(key);
       if ( f == map.end())
         throw std::out_of_range("key not found");
       return f->second;
    }