天天看點

C++(STL):30 ---關聯式容器map的operator[]和insert效率對比

通過前面的學習我們知道,map 容器模闆類中提供有 operator[ ] 和 insert() 這 2 個成員方法,而值得一提的是,這 2 個方法具有相同的功能,它們既可以實作向 map 容器中添加新的鍵值對元素,也可以實作更新(修改)map 容器已存儲鍵值對的值。舉個例子(程式一):

#include <map>  //map
#include <string> //string
#include <iostream>
using namespace std;


int main()
{
  std::map<string, string> mymap;
  //借用 operator[] 添加新鍵值對
  mymap["player_01"] = "{\"username\":\"Bear\",\"deviceid\":\"baf8700ac280467fcaf581520dc510ebf1c61c42_3400_MS - 7C02(Micro - Star International Co., Ltd)\"}";
  cout << string("old mymap:") << mymap["player_01"] << endl;
  //借用 operator[] 更新某個鍵對應的值
  mymap["player_01"] = "{\"username\":\"Horse\",\"deviceid\":\"caf8700ac280467fcaf581520dc510ebf1c61c42_3400_MS - 7C02(Micro - Star International Co., Ltd)\"}";
  cout << "new mymap:" << mymap["player_01"] << endl;




  //借用insert()添加新鍵值對
  std::pair<string, string> STL = { "Javaplayer_02","{\"username\":\"C++\",\"deviceid\":\"qaf8700ac280467fcaf581520dc510ebf1c61c42_3400_MS - 7C02(Micro - Star International Co., Ltd)\"}" };
  std::pair<std::map<string, string>::iterator, bool> ret;
  ret = mymap.insert(STL);
  cout << "old ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << endl;
  //借用 insert() 更新鍵值對
  mymap.insert(STL).first->second = "node js";
  cout << "new ret.iter = <" << ret.first->first << ", " << ret.first->second << ">" << endl;
  return 0;
}      

程式執行結果為:

old mymap:{"username":"Bear","deviceid":"baf8700ac280467fcaf581520dc510ebf1c61c42_3400_MS - 7C02(Micro - Star International Co., Ltd)"}
new mymap:{"username":"Horse","deviceid":"caf8700ac280467fcaf581520dc510ebf1c61c42_3400_MS - 7C02(Micro - Star International Co., Ltd)"}
old ret.iter = <{Javaplayer_02, {"username":"C++","deviceid":"qaf8700ac280467fcaf581520dc510ebf1c61c42_3400_MS - 7C02(Micro - Star International Co., Ltd)"}}, 1>
new ret.iter = <Javaplayer_02, node js>      
有關程式中 operator[ ] 和 insert() 成員方法的具體用法,讀者可翻閱前面的文章做詳細了解,這裡不再做過多解釋。

顯然,map 模闆類中 operator[ ] 和 insert() 的功能發生了重疊,這就産生了一個問題,誰的執行效率更高呢?

總的來說,讀者可記住這樣一條結論:當實作“向 map 容器中添加新鍵值對元素”的操作時,insert() 成員方法的執行效率更高;而在實作“更新 map 容器指定鍵值對的值”的操作時,operator[ ] 的效率更高。

至于為什麼,有興趣的讀者可繼續往下閱讀。

向map容器中增添元素,insert()效率更高

首先解釋一下,為什麼實作向 map 容器中添加新鍵值對元素,insert() 方法的執行效率比 operator[ ] 更高?回顧程式一中,如下語句完成了向空 mymap 容器添加新的鍵值對元素:

mymap["player_01"] = "{\"username\":\"Horse\",\"deviceid\":\"caf8700ac280467fcaf581520dc510ebf1c61c42_3400_MS - 7C02(Micro - Star International Co., Ltd)\"}";      

此行代碼中,mymap["player_01"] 實際上是 mymap.operator[ ](“STL教程”) 的縮寫(底層調用的 operator[ ] 方法),該方法會傳回一個指向 “STL教程” 對應的 value 值的引用。

但需要注意的是,由于此時 mymap 容器是空的,并沒有 "STL教程" 對應的 value 值。這種情況下,operator[ ] 方法會預設構造一個 string 對象,并将其作為 "STL教程" 對應的 value 值,然後傳回一個指向此 string 對象的引用。在此基礎上,代碼還會将 "{\"username\":\"Horse\",\"deviceid\":\"caf8700ac280467fcaf581520dc510ebf1c61c42_3400_MS - 7C02(Micro - Star International Co., Ltd)\"}" 指派給這個 string 對象。

也就是說,上面這行代碼的執行流程,可以等效為如下程式:

typedef map<string, string> mstr;
//建立要添加的預設鍵值對元素
pair<mstr::iterator, bool>res = mymap.insert(mstr::value_type("player_01", string()));
//将新鍵值對的值指派為指定的值
res.first->second = "{\"username\":\"Horse\",\"deviceid\":\"caf8700ac280467fcaf581520dc510ebf1c61c42_3400_MS - 7C02(Micro - Star International Co., Ltd)\"}";      
注意,這裡的 value_type(K,T) 指的是 map 容器中存儲元素的類型,其實際上就等同于 pair<K,T>。

可以看到,使用 operator[ ] 添加新鍵值對元素的流程是,先構造一個有預設值的鍵值對,然後再為其 value 指派。

那麼,為什麼不直接構造一個要添加的鍵值對元素呢,比如:

mymap.insert(mstr::value_type("C++", "脫發嚴重"));

此行代碼和上面程式的執行效果完全相同,但它省略了建立臨時 string 對象的過程以及析構該對象的過程,同時還省略了調用 string 類重載的指派運算符。由于可見,同樣是完成向 map 容器添加新鍵值對,insert() 方法比 operator[ ] 的執行效率更高。

更新map容器中的鍵值對,operator[]效率更高

仍以程式一中的代碼為例,如下分别是 operator[ ] 和 insert() 實作更新 mymap 容器中指定鍵對應的值的代碼:

//operator[]
mymap["C++"] = "脫發";
//insert()
std::pair<string, string> STL = { "node","霸王洗髮乳" };
mymap.insert(STL).first->second = "還是霸王洗髮乳好";      

僅僅從文法形式本身來考慮,或許已經促使很多讀者選擇 operator[ ] 了。

接下來,我們再從執行效率的角度對比以上 2 種實作方式。

從上面代碼可以看到,insert() 方法在進行更新操作之前,需要有一個 pair

類型(也就是 map::value_type 類型)元素做參數。這意味着,該方法要多

構造一個 pair 對象(附帶要構造 2 個 string 對象),并且事後還要析構此

pair 對象(附帶 2 個 string 對象的析構)。而和 insert() 方法相比,

operator[ ] 就不需要使用 pair 對象,自然不需要構造(并析構)任何 pair

對象或者 string 對象。是以,對于更新已經存儲在 map 容器中鍵值對的值,