2013-10-24 76 views
2

我只能使用C++ 98,並且無法訪問使用C++ 11添加的std::map::at()的實現。C++ 98 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; 
} 

我至少可以看到一個問題,就是我的版本的行爲就好像我又回到副本(見下文)。

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. 我的包裝有任何其他問題嗎?
+3

你應該find'的'結果存儲在一個變量爲了不遍歷地圖兩次。 –

+0

這個問題似乎是脫離主題,因爲它是關於什麼相當於一個錯字。 –

+0

@KubaOber我不同意。這個問題更多的是缺乏理解爲什麼通過值傳遞'map'不會修改元素而不是簡單的錯字。操作準則顯然不明白爲什麼按價值傳遞它不能像預期的那樣工作。 –

回答

10

的主要問題是,你調用未定義的行爲。

at由值取圖:

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

所以你在本地的對象,這是非常不確定的返回一個參考項。

你應該使用一個參考:

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

你可能要添加的量版本,以及:

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

那,並命名一個'std :: map'實例'map'就是一種可怕的形式...... –

2

更改簽名

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

你AVE在方法2個問題:

  • 您將map實例作爲值傳遞,這樣不僅可以複製整個映射,還可以返回對該本地副本中元素的引用並生成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; 
}