這篇主要想記錄一下 const map 想要利用 [] operator 存取元素時會遇到的問題與解決方式。
首先一般我們常會利用 [] operator 來存取, 賦值給 map 中的元素,例如:
map<int, int> m;
m[0] = 1;
m[1] = 2;
cout<<m[1]<<endl;
但是今天如果這個 map 是 const 的則就不能夠使用 [] operator,例如:
const auto const_map = m;
cout<<m[0]<<endl; // compiler error: error: passing ‘const std::map<int, int>’ as ‘this’ argument discards qualifiers [-fpermissive]
這是因為 non-const 的 member function 使用了 const 的 data member,因為 const_map 被宣告
為 const 的 object 所以它的 data member 也都是 const 的,而 map 的 [] operator 並沒有 const 版
本的 overloading,可以參考 C++ reference , map [] operator 的定義:
mapped_type& operator[] (const key_type& k);
mapped_type& operator[] (key_type&& k);衍伸的問題是其他的 STL container 有 const 版本的 [] operator (ex: vector) ,為何 map 不提供?vector [] operator 定義:reference operator[] (size_type n);
const_reference operator[] (size_type n) const;原因可以在 map stl 的實現中找到,以下是某版本的 map stl 中 [] operator 的實作(各版之間差異不大)mapped_type& operator[](key_type&& __k) {
// concept requirements
__glibcxx_function_requires(_DefaultConstructibleConcept<mapped_type>)
iterator __i = lower_bound(__k);
// __i->first is greater than or equivalent to __k.
if (__i == end() || key_comp()(__k, (*__i).first))
__i = _M_t._M_emplace_hint_unique(__i, std::piecewise_construct,
std::forward_as_tuple(std::move(__k)),
std::tuple<>());
return (*__i).second;} 在 [] operator 的實作中,會先用 binary search 找到 input 的 Key 值,如果該 key 值不存在於 map中,則 map 會賦予該 key 值一個 default 的 value 並存入 map中,因此可以發現這個操作會有機會改動到map本身,因此是個 non-const的操作,這注定了 [] operator 不可能為 const function。所以遇到想在 const map 中存取元素的情況就必須使用有 const 操作的 .at() 或是 find() 函數。map::finditerator find (const key_type& k);
const_iterator find (const key_type& k) const;map::atmapped_type& at (const key_type& k);
const mapped_type& at (const key_type& k) const;* map.at() 在遇到不存在的 key 值時跟 vector.at() 一樣會丟出 out_of_range exception.
沒有留言:
張貼留言