1. 程式人生 > 實用技巧 >講解有4種方式C++ STL map insert()插入資料

講解有4種方式C++ STL map insert()插入資料

前面講過,C++STLmap 類模板中對[ ]運算子進行了過載,即根據使用場景的不同,藉助[ ]運算子可以實現不同的操作。舉個例子:

#include <iostream>
#include <map>  //map
#include <string> //string
using namespace std;
int main()
{
    std::map<string, string> mymap{ {"STL教程","http:///java/"} };
    //獲取已儲存鍵值對中,指定鍵對應的值
    cout << mymap["STL教程"] << endl;
    //向 map 容器新增新鍵值對
    mymap["Python教程"] = "http:///python/";
    //修改 map 容器已儲存鍵值對中,指定鍵對應的值
    mymap["STL教程"] = "http:///stl/";
    for (auto iter = mymap.begin(); iter != mymap.end(); ++iter) {
        cout << iter->first << " " << iter->second << endl;
    }
   
    return 0;
}

  

程式執行結果為:

http:///java/
Python教程 http:///python/
STL教程 http:///stl/

  

可以看到,當操作物件為 map 容器中已儲存的鍵值對時,則藉助 [ ] 運算子,既可以獲取指定鍵對應的值,還能對指定鍵對應的值進行修改;反之,若 map 容器內部沒有儲存以 [ ] 運算子內指定資料為鍵的鍵值對,則使用 [ ] 運算子會向當前 map 容器中新增一個新的鍵值對。

實際上,除了使用 [ ] 運算子實現向 map 容器中新增新鍵值對外,map 類模板中還提供有insert()成員方法,該方法專門用來向 map 容器中插入新的鍵值對。

注意,這裡所謂的“插入”,指的是 insert() 方法可以將新的鍵值對插入到 map 容器中的指定位置,但這與 map 容器會自動對儲存的鍵值對進行排序並不衝突。當使用 insert() 方法向 map 容器的指定位置插入新鍵值對時,其底層會先將新鍵值對插入到容器的指定位置,如果其破壞了 map 容器的有序性,該容器會對新鍵值對的位置進行調整。

自 C++ 11 標準後,insert() 成員方法的用法大致有以下 4 種。

1) 無需指定插入位置,直接將鍵值對新增到 map 容器中。insert() 方法的語法格式有以下 2 種:

//1、引用傳遞一個鍵值對
pair<iterator,bool> insert (const value_type& val);
//2、以右值引用的方式傳遞鍵值對
template <class P>
    pair<iterator,bool> insert (P&& val);

  

其中,val 引數表示鍵值對變數,同時該方法會返回一個 pair 物件,其中 pair.first 表示一個迭代器,pair.second 為一個 bool 型別變數:

  • 如果成功插入 val,則該迭代器指向新插入的 val,bool 值為 true;
  • 如果插入 val 失敗,則表明當前 map 容器中存有和 val 的鍵相同的鍵值對(用 p 表示),此時返回的迭代器指向 p,bool 值為 false。

以上 2 種語法格式的區別在於傳遞引數的方式不同,即無論是區域性定義的鍵值對變數還是全域性定義的鍵值對變數,都採用普通引用傳遞的方式;而對於臨時的鍵值對變數,則以右值引用的方式傳參。有關右值引用,可閱讀《C++右值引用》一文做詳細瞭解。

舉個例子:

#include <iostream>
#include <map>  //map
#include <string> //string
using namespace std;
int main()
{
    //建立一個空 map 容器
    std::map<string, string> mymap;
   
    //建立一個真實存在的鍵值對變數
    std::pair<string, string> STL = { "STL教程","http:///stl/" };
   
    //建立一個接收 insert() 方法返回值的 pair 物件
    std::pair<std::map<string, string>::iterator, bool> ret;
   
    //插入 STL,由於 STL 並不是臨時變數,因此會以第一種方式傳參
    ret = mymap.insert(STL);
    cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << endl;
    //以右值引用的方式傳遞臨時的鍵值對變數
    ret = mymap.insert({ "C語言教程","/c/" });
    cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << endl;
    //插入失敗樣例
    ret = mymap.insert({ "STL教程","/java/" });
    cout << "ret.iter = <{" << ret.first->first << ", " << ret.first->second << "}, " << ret.second << ">" << endl;
    return 0;
}

足球前瞻

程式執行結果為:

ret.iter = <{STL教程, http:///stl/}, 1>
ret.iter = <{C語言教程, http:///c/}, 1>
ret.iter = <{STL教程, http:///stl/}, 0>

  

從執行結果中不難看出,程式中共執行了 3 次插入操作,其中成功了 2 次,失敗了 1 次:

  • 對於插入成功的 insert() 方法,其返回的 pair 物件中包含一個指向新插入鍵值對的迭代器和值為 1 的 bool 變數
  • 對於插入失敗的 insert() 方法,同樣會返回一個 pair 物件,其中包含一個指向 map 容器中鍵為 "STL教程" 的鍵值對和值為 0 的 bool 變數。


另外,在程式中的第 21 行程式碼,還可以使用如下 2 種方式建立臨時的鍵值對變數,它們是等價的:

//呼叫 pair 類模板的建構函式
ret = mymap.insert(pair<string,string>{ "C語言教程","http:///c/" });
//呼叫 make_pair() 函式
ret = mymap.insert(make_pair("C語言教程", "http:///c/"));

  

2) 除此之外,insert() 方法還支援向 map 容器的指定位置插入新鍵值對,該方法的語法格式如下:

//以普通引用的方式傳遞 val 引數
iterator insert (const_iterator position, const value_type& val);
//以右值引用的方式傳遞 val 鍵值對引數
template <class P>
    iterator insert (const_iterator position, P&& val);

  

其中 val 為要插入的鍵值對變數。注意,和第 1 種方式的語法格式不同,這裡 insert() 方法返回的是迭代器,而不再是 pair 物件:

  • 如果插入成功,insert() 方法會返回一個指向 map 容器中已插入鍵值對的迭代器;
  • 如果插入失敗,insert() 方法同樣會返回一個迭代器,該迭代器指向 map 容器中和 val 具有相同鍵的那個鍵值對。


舉個例子:

#include <iostream>
#include <map>  //map
#include <string> //string
using namespace std;
int main()
{
    //建立一個空 map 容器
    std::map<string, string> mymap;
   
    //建立一個真實存在的鍵值對變數
    std::pair<string, string> STL = { "STL教程","http:///stl/" };
    //指定要插入的位置
    std::map<string, string>::iterator it = mymap.begin();
    //向 it 位置以普通引用的方式插入 STL
    auto iter1 = mymap.insert(it, STL);
    cout << iter1->first << " " << iter1->second << endl;
    //向 it 位置以右值引用的方式插入臨時鍵值對
    auto iter2 = mymap.insert(it, std::pair<string, string>("C語言教程", "http:///c/"));
    cout << iter2->first << " " << iter2->second << endl;
    //插入失敗樣例
    auto iter3 = mymap.insert(it, std::pair<string, string>("STL教程", "http:///java/"));
    cout << iter3->first << " " << iter3->second << endl;
    return 0;
}

  

程式執行結果為:

STL教程 http:///stl/
C語言教程 http:///c/
STL教程 http:///stl/

nba前瞻

再次強調,即便指定了新鍵值對的插入位置,map 容器仍會對儲存的鍵值對進行排序。也可以說,決定新插入鍵值對位於 map 容器中位置的,不是 insert() 方法中傳入的迭代器,而是新鍵值對中鍵的值。

3) insert() 方法還支援向當前 map 容器中插入其它 map 容器指定區域內的所有鍵值對,該方法的語法格式如下:

template <class InputIterator>
  void insert (InputIterator first, InputIterator last);

  

其中 first 和 last 都是迭代器,它們的組合<first,last>可以表示某 map 容器中的指定區域。

舉個例子:

#include <iostream>
#include <map>  //map
#include <string> //string
using namespace std;
int main()
{
    //建立並初始化 map 容器
    std::map<std::string, std::string>mymap{ {"STL教程","/stl/"},
                                                {"C語言教程","http:///c/"},
                                                {"Java教程","http:///java/"} };
    //建立一個空 map 容器
    std::map<std::string, std::string>copymap;
    //指定插入區域
    std::map<string, string>::iterator first = ++mymap.begin();
    std::map<string, string>::iterator last = mymap.end();
    //將<first,last>區域內的鍵值對插入到 copymap 中
    copymap.insert(first, last);
    //遍歷輸出 copymap 容器中的鍵值對
    for (auto iter = copymap.begin(); iter != copymap.end(); ++iter) {
        cout << iter->first << " " << iter->second << endl;
    }
    return 0;
}

  

程式執行結果為:

Java教程 http:///java/
STL教程 http:///stl/

  

此程式中,<first,last> 指定的區域是從 mumap 容器第 2 個鍵值對開始,之後所有的鍵值對,所以 copymap 容器中包含有 2 個鍵值對。

4) 除了以上一種格式外,insert() 方法還允許一次向 map 容器中插入多個鍵值對,其語法格式為:

void insert ({val1, val2, ...});

  

其中,vali都表示的是鍵值對變數。

舉個例子:

#include <iostream>
#include <map>  //map
#include <string> //string
using namespace std;
int main()
{
    //建立空的 map 容器
    std::map<std::string, std::string>mymap;
    //向 mymap 容器中新增 3 個鍵值對
    mymap.insert({ {"STL教程", "http:///stl/"},
                   { "C語言教程","http:///c/" },
                   { "Java教程","http:///java/" } });
    for (auto iter = mymap.begin(); iter != mymap.end(); ++iter) {
        cout << iter->first << " " << iter->second << endl;
    }
    return 0;
}

  

程式執行結果為:

C語言教程 http:///c/
Java教程 http:///java/
STL教程 http:///stl/

  

值得一提的是,除了 insert() 方法,map 類模板還提供 emplace() 和 emplace_hint() 方法,它們也可以完成向 map 容器中插入鍵值對的操作,且效率還會 insert() 方法高。關於這 2 個方法,會在下一節做詳細介紹。