1. 传参方式
使用 insert 为 map 插值时,insert 的传参包含以下几种可能:
- make_pair 生成对象
- pair(key_type, value_type) 生成对象
- pair(const key_type, value_type) 生成对象
- map<key_type, value_type>::value_type 生成对象
不同的传参,导致不同次数的构造 / 析构函数调用。
2. 测试代码与结果
/*
在 map 中不同的 insert 传参类型,导致的不同次数的构造/析构函数调用。
*/ #include <iostream>
#include <vector>
#include <map>
#include <string> using namespace std; class Data
{
public:
Data(void)
{
cout << "Constructor" << endl;
} Data(const Data& other)
{
cout << "Copy Constructor" << endl;
} Data& operator=(const Data& other)
{
cout << "Assignment operator" << endl;
return *this;
} ~Data(void)
{
cout << "Destructor" << endl;
}
}; class Tracker
{
public:
Tracker(string name)
{
_name = name;
cout << "### Testing " << name << endl;
} ~Tracker(void)
{
cout << "### Done" << endl << endl;
} private:
string _name;
}; int main () {
{
Tracker tracker("insert data using make_pair");
map<int, Data> c;
Data d = Data();
cout << "---- Begin ---- " << endl;
c.insert(make_pair(, d));
cout << "----- End -----" << endl;
} {
Tracker tracker("insert data using pair<key_type, value_type>");
map<int, Data> c;
Data d = Data();
cout << "---- Begin ---- " << endl;
c.insert(pair<int, Data>(, d));
cout << "----- End -----" << endl;
} {
Tracker tracker("insert data using pair<const key_type, value_type>");
map<int, Data> c;
Data d = Data();
cout << "---- Begin ---- " << endl;
c.insert(pair<const int, Data>(, d));
cout << "----- End -----" << endl;
} {
Tracker tracker("insert data using map<key_type, value_type>::value_type");
map<int, Data> c;
Data d = Data();
cout << "---- Begin ---- " << endl;
c.insert(map<int, Data>::value_type(, d));
cout << "----- End -----" << endl;
} return ;
}
3. 调用流程分析
3.1 value_type 2 次 Copy Constructor 产生 1 个临时变量
分解后的 value_type 调用细节对比图
- 构造 value_type 的临时变量,一次 Copy Constructor
- insert value_type 类型的参数,一次 Copy Constructor
- 析构 value_type 的临时变量,一次 Destructor
3.2 pair(const key_type, value_type) 与 value_type 过程相同
原因:value_type 的定义是: pair<const key_type,mapped_type>
参见:http://www.cplusplus.com/reference/map/map/
3.3 pair(key_type, value_type) 3 次 Copy Constructor 产生 2 个临时变量
根据下图的流程拆解可以看出,非 const 的 key_type 导致 insert 过程增加了一次 Copy Constructor
3.4 make_pair 4 次 Copy Constructor 产生 3 个临时变量
新增的一次 Copy Constructor 来自于 make_pair 过程。
make_pair 的过程是:Constructs a pair object with its first element set to x and its second element set to y.
伪代码如下:
template <class T1,class T2>
pair<T1,T2> make_pair (T1 x, T2 y)
{
return ( pair<T1,T2>(x,y) );
}
参见:http://www.cplusplus.com/reference/utility/make_pair/?kw=make_pair
make_pair 时的 key 使用 const 变量,并未能减少 insert 阶段的一次 Copy Constructor
const int k = ;
c.insert(make_pair(k, d));
4. 结果分析
- insert 时,如果 key_type 不是 const 类型, 则增加一次 Copy Constructor
- make_pair 无法产生 const key_type 的 pair,导致 insert 增加一次 Copy Constructor
- map<key, value>::value_type 的 key 是 const 类型,使用简单,性能好。