C++ map.insert 传参类型不同,构造/析构次数不同

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(1, 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>(1, 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>(1, 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(1, d));
        cout << "----- End -----" << endl;
    }

    return 0;
}

3. 调用流程分析

3.1 value_type 2 次 Copy Constructor 产生 1 个临时变量

分解后的 value_type 调用细节对比图

  1. 构造 value_type 的临时变量,一次 Copy Constructor
  2. insert value_type 类型的参数,一次 Copy Constructor
  3. 析构 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 = 1;
c.insert(make_pair(k, d));

4. 结果分析

  1. insert 时,如果 key_type 不是 const 类型, 则增加一次 Copy Constructor
  2. make_pair 无法产生 const key_type 的 pair,导致 insert 增加一次 Copy Constructor
  3. map<key, value>::value_type 的 key 是 const 类型,使用简单,性能好。

C++ map.insert 传参类型不同,构造/析构次数不同

时间: 2024-12-09 10:23:17

C++ map.insert 传参类型不同,构造/析构次数不同的相关文章

LiveBOS Webservice传参类型为list数组

昨天有使用soap传输数据到Webservice,其中字符串类型的都已经传输成功,但是有几个参数传输失败,java服务器端收到的空值. 因为我是php的,然后接收端是java制作的,其中有几个参数是list数组类型的,我刚开始将php的数组传过去,服务端接收到的是空,然后再使用json格式还是不行.后来去询问java同事,他们说list数组类型不像php一样是有键值和键名的, java的list数组是只有name和value对应关系,如下所示 $arr = array('userid'=>1,'

mybatis传参

1. 概念 mybatis的传参即通过dao的方法映射mapper.xml配置文件中的方法操作数据库 无论传递的参数是什么样的,最后mybtis都会将传入的转换为map mybatis传参可以分为两个部分 参数的数量 参数的类型 2. 按参数的数量 2.1 单个参数传递 @param可以不用写,如果写上就要求和mapper文件中的参数一致 public List<XXBean> getXXBeanList(@param("id")String id); <select

(二)Mybatis类型转换器,接口传参类型,

Mybatis类型转换器 首先明白什么时候用到它,当数据库的字段类型和java字段类型无法默认匹配时候进行转换,比如现在数据库类型是INTEGER,而java当中类型是Boolean,true表示1,false表示0,这时候你在执行sql语句插入或者查询获取结果集时,类型就会出现不匹配的情况,这时候我们只需要书写一个类型转换器,并进行配置,之后java遇到INTEGER---Boolean两个类型的时候,就会帮我们自动转换,相当于你插入数据库的值传的是true,他就会转换成1然后插入,数据库返回

c++代码赏析之类对象传参

#include <iostream> using namespace std; class A { private: int x; public: A():x(0) { x = 0; cout << "construct" << endl; } A(const A &a) { x = a.x; cout << "construct copy" << endl; } ~A(){ cout <&

RestTemplate post请求使用map传参 Controller 接收不到值的解决方案 postForObject方法源码解析.md

结论 post方法中如果使用map传参,需要使用MultiValueMap来传递 RestTemplate 的 postForObject 方法有四个参数 String url => 顾名思义 这个参数是请求的url路径 Object request => 请求的body 这个参数需要再controller类用 @RequestBody 注解接收 Class responseType => 接收响应体的类型 第四个参数?postForObject 方法多种重构 Map<String

控制器向视图传参ModelAndView、Model和Map

ModelAndView类 ModelAndView在spring-webmvc-4.3.18.RELEASE.jar包下,当然其他版本也有,所在包如下 创建controller,访问地址并传参http://localhost:8080/index?username=yanguobin 通过EL表达式在jsp中获取 Model接口 Model在spring-context-4.3.18.RELEASE.jar包下,当然其他版本也有,是一个接口,所在包如下 可以使用Model对象来完成模型数据的传

dynamic结合匿名类型 匿名对象传参

首先说明下,我一般很少用dynamic关键字(类)的,因为毕竟是由反射实现的,所以对于性能方面还是吃亏不少(注:由于心里没底,查了一些资料得知,dynamic实质上好像不是由反射实现的,其性能也比直接反射要高不少,至于为什么,我也不明白,希望你们知道的能留言告诉我一下!谢谢啦 ^_^)我也不知道为什么DLR能够实现与反射一样的实现,但代码,性能要比后者简介,高效!! 我这里就纯粹在这里坐下记录 匿名对象(类型)传参的几种方式 代码如下: class Program { static void M

.NET 内存基础(通过内存体验类型、传参、及装箱拆箱)

该随笔受启发于<CLR Via C#(第三版)>第四章4.4运行时的相互联系 一.内存分配的几个区域 1.线程栈 局部变量的值类型 和 局部变量中引用类型的指针(或称引用)会被分配到该区域上(引用类型的一部分内存被分配到该区域内). 该区域由系统管控,不受垃圾收集器的控制.当所在方法执行完毕后,局部变量会自动释放(引用类型只释放指针,而不释放指针指向的数据). 堆栈的执行效率很高,但容量有限. 2.GC Heap(回收堆) 用于分配小对象(引用类型),如果引用类型的实例大小 小于85000个字

枚举|标志枚举+|(或)和&amp;(与)运算|类型转换|值类型和引用类型|传参|异常|垃圾回收

枚举部分 enum 关键字用于声明枚举,即一种由一组称为枚举数列表的命名常量组成的独特类型. 通常情况下,最好是在命名空间内直接定义枚举,以便该命名空间中的所有类都能够同样方便地访问它. 但是,还可以将枚举嵌套在类或结构中.默认情况下,第一个枚举数的值为 0,后面每个枚举数的值依次递增 1. 例1: //此枚举的默认值是从0开始 enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri}; 例2: //此枚举的默认值是从1开始,下标为3的tue值为7,从下标3开始