C++98 Wrapper for std::map::at()

C++98 Wrapper for std::map::at()

本文关键字:at map C++98 for std Wrapper      更新时间:2023-10-16

>我只能使用 C++98,并且无法访问与 C++11 一起添加的std::map::at()的嵌入。

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

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

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

可以看到至少一个问题,那就是我的版本表现得好像我返回了副本一样(见下文)。

std::map<int,int> myMap;
myMap.insert(std::pair<int,int>(2,43));
// myMap.at(2)=44;            // modifies the reference
// assert(44==myMap.at(2));   // fine 
at(myMap,2)=44;               // does not modify the value inside the map, why?
assert(44==myMap.at(2));      // not fine
  1. 如何解决此问题?
  2. 我的包装器还有其他问题吗?

主要问题是你正在调用未定义的行为。

您的at按值获取地图:

V& at(std::map<K, V> map, K key)

因此,您返回的是对本地对象中项的引用,这是非常未定义的。

您应该使用引用:

V& at(std::map<K, V>& map, const K& key)

您可能还想添加 const 版本:

const V& at(const std::map<K, V>& map, const K& key)

将签名更改为

V& at(std::map<K, V>& map, K key)

您的方法中有 2 个问题:

  • 您将映射实例作为值传递,因此不仅可以复制整个映射,还可以返回对该本地副本中元素的引用并生成 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;
}