[英]When I should use std::map::at to retrieve map element
我已經在stackoverflow上閱讀了關於web和問題的不同文章,但是對於我來說,當使用std::map::at
來檢索map元素更好時,還不清楚是否存在任何獨有的情況。
根據定義 , std::map::at
返回對使用鍵k標識的元素的映射值的引用。
如果k與容器中任何元素的鍵不匹配,則該函數拋出out_of_range異常。
對我來說只有當你100%確定存在具有特定鍵的元素時才值得使用std::map::at
,否則你應該考慮異常處理。
std::map::at
被認為是最有效和優雅的方式? 在什么情況下你會建議使用std::map::at
? map::find()
嗎? 而map::find()
它是更快更優雅的方法嗎? if ( map.find("key") != map.end() ) { // found } else { // not found }
PS
map::operator[]
有時可能很危險,因為如果一個元素不存在,那么它會插入它。
與此處的大多數現有答案相反,請注意實際上有4種與在地圖中查找元素相關的方法(忽略lower_bound
, upper_bound
和equal_range
,這些方法不太精確):
operator[]
僅存在於非const版本中,如上所述,如果元素不存在,它將創建該元素 at()
,在C ++ 11中引入,如果元素存在則返回對該元素的引用,否則拋出異常 find()
返回一個迭代器,如果不存在,則返回map::end()
的迭代器 count()
返回這些元素的數量,在map
,這是0或1 既然語義很清楚,那么讓我們來看看何時使用哪個:
map
是否存在元素(或不存在),則使用count()
。 map
,然后使用at()
。 map
,那么使用find()
; 不要忘記檢查生成的迭代器是否不等於end()
的結果。 operator[]
; 如果您不希望調用類型默認構造函數來創建它,那么請適當地使用insert
或emplace
如果找不到該元素, std::map::at()
會拋出out_of_range
異常。 這個異常是一種logic_error
異常,從使用的角度來看,對我來說這是一種assert()
的同義詞:它應該用於報告程序內部邏輯中的錯誤,比如違反邏輯前置條件或類不變量。
此外,您可以使用at()
來訪問const映射。
所以,對於你的問題:
at()
訪問const映射時使用at()
而不是[]
,當元素缺失是邏輯錯誤時。 map::find()
:在這種情況下,它不是邏輯錯誤,因此拋出和捕獲std::logic_error
異常將不是非常優雅的編程方式,甚至如果我們不考慮表現。 如您所述,有三種不同的方法可以訪問地圖中的元素: at()
, operator[]
和find()
(還有upper_bound
, lower_bound
和equal_range
,但這些方法適用於您可能想要查找的更復雜的情況下一個/上一個元素等)
那么,你什么時候應該使用哪一個?
operator[]
基本上是“如果它不存在,則使用默認構造的映射元素創建一個”。 這意味着它不會拋出(除非在內存分配拋出或其中一個鍵或值構造函數拋出的角落情況下),並且您肯定會獲得對您查找的元素的引用 - 現有元素或新創建的元素。
如果該鍵沒有元素,則at()
拋出。 由於您不應該使用異常來處理正常的程序流,因此使用at()
表示“我確信存在這樣的元素”。 但如果你錯了,你會得到一個例外(而不是未定義的行為)的額外好處。 如果您不確定該元素是否存在,請不要使用此方法。
find()
說“可能有也可能沒有這樣的元素,讓我們看看......”並為您提供以不同方式對兩種情況作出反應的可能性。 因此,它是更通用的方法。
所有3個find
, operator[]
和at
都很有用。
如果你不想意外地插入元素,那么find
是好的,但只要它們存在就行動。
at
如果你期望的東西應該是一個地圖上,你會拋出一個異常,如果不是反正是好的。 它還可以比find
更簡潔地訪問const
映射(在那里你不能使用op[]
)
如果你想插入一個默認元素, op[]
是好的,例如對於單詞計數程序,它為第一次遇到的每個單詞設置一個int 0
(用成語words[word]++;
)。
這取決於此功能的要求以及您如何構建項目。 如果你應該返回一個對象但你不能因為它沒有被找到,那么它將為你提供兩個如何處理它的選項。 你可以通過一個例外,或者你可以返回某種哨兵,這意味着沒有找到任何東西。 如果要拋出異常,則使用at()
因為異常將為您拋出。 如果您不想拋出異常,那么使用find()
這樣您就不必處理異常只是為了返回一個sentinel對象。
我認為,這取決於你的用例。 std::map::at()
的返回類型是對找到的元素的值的左值引用,而std::map::find()
返回一個迭代器。 你可能更喜歡
return myMap.at("asdf"s) + 42;
在表達式上更精細
return myMap.find("asdf"s)->second + 42;
每當在表達式中使用std::map::at()
的結果時,您希望該元素存在,並將缺少的元素視為錯誤。 所以異常是處理它的好選擇。
我猜不同之處在於語義。
std::map::at()
在我的機器上看起來像這樣:
mapped_type&
at(const key_type& __k)
{
iterator __i = lower_bound(__k);
if (__i == end() || key_comp()(__k, (*__i).first))
__throw_out_of_range(__N("map::at"));
return (*__i).second;
}
如您所見,它使用lower_bound
,然后檢查end()
,比較密鑰,並在需要時拋出異常。
find()
看起來像這樣:
iterator
find(const key_type& __x)
{ return _M_t.find(__x); }
其中_M_t
是存儲實際數據的紅黑樹。 顯然,兩個函數都具有相同的(對數)復雜度。 當你使用find()
+ check for end()
,你做的幾乎和at
一樣。 我會說語義上的區別是:
at()
,並假設它在那里。 在這種情況下,從所需位置丟失的元素的情況是例外的,因此at()
拋出異常。 find()
。 在這種情況下,元素不存在的情況是正常的。 另請注意, find()
返回一個迭代器,您可以將其用於除了簡單獲取值之外的其他目的。 map :: at()返回一個l值引用,當您通過引用返回時,可以使用其所有可用的好處,例如方法鏈。
例:
map<int,typ> table;
table[98]=a;
table[99]=b;
table.at(98)=table.at(99);
operator[]
也通過引用返回映射值,但是如果找不到找到的鍵,它可能會插入一個值,在這種情況下,容器大小會增加1。
這需要您格外小心,因為您必須處理迭代器失效 。
我是對的,當有可能沒有帶有這樣一個鍵的元素時,最好使用map :: find()嗎? 而map :: find()它是更快更優雅的方法嗎?
是的,從語義上講,當你不確定是否存在元素時使用find()是有意義的。即使對於新手來說,代碼也更容易理解。
至於時間效率,map通常實現為RB樹/一些平衡二叉搜索樹,因此,find()的復雜度為O(logN)。
C ++規范:
T&operator [](const key_type&x);
效果:如果地圖中沒有等效於x的鍵,則將value_type(x,T())插入到地圖中。 要求:key_type應為CopyInsertable,而mapped_type應為DefaultInsertable為* this。 返回:對* this中x對應的mapped_type的引用。 4復雜性:對數。T&at(const key_type&x);
const T&at(const key_type&x)const; 返回:對* this中x對應的mapped_type的引用。 拋出:如果沒有這樣的元素,則為out_of_range類型的異常對象。 復雜性:對數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.