Leehm

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

1.  往map里面插入元素:

        下标方式[]:    map[key] = value;                                

        调用insert:       map.insert(make_pair(key, value));   

        下标方式是通过重载[]操作符来实现的,它直接进行插入或覆盖,

         insert方法会判断是否存在相同的key,如果存在则直接返回,放弃插入操作。如果不存在才进行插入

 

2.   从map里面获取元素

       下标方式:       if()value = map[key];

        迭代器方式:  value =  itor->second;

        需要检查key是否存在,如果不存在,map[key]返回就是未知,而不是null,因为这时会在map中插入一个key的元素,value取默认值,返回value,所以未知,是很危险的操作,建议使用迭代器的方式,会习惯性的去判断itor指针是否合法。

        如下:仅供参考

if(map.count(key)>0)   //count(key)  0:not in map, 1:in 
{
    return map[key];
}

itor = map.find(key);
if(itor!=map.end())
{
    return itor->second;
}

  下标方法很直观,但是效率差很多。因为需要执行两次查找,因此,无论从安全性还是效率考虑,都推荐使用后一种方法。

 

3.  map元素的删除

      auto itor_next = map.erase(itor);   

      //c++11 中返回的是移除元素后的下一个迭代器这个参数必须是容器中的有效迭代器,不能是结束迭代器。如果迭代器参数指向的是容器的最后一个元素,那么会返回结束迭代器

      // list的earse也是返回下一个

     list遍历删除,仅供参考

for (itor = list->begin(); itor != list->end();  )
{
	if(itor == delete)
	{
                //返回下一个元素itor,需要赋值以便后续遍历
		itor =list->erase(itor);

              //list->erase(it); itor++      //错误,当前itor已经删除,itor++会crash 
              //list->erase(it++);            //正确, 
	}
        else
        {
		it++;
	}		
}

        元素删除内存管理:

         如果其中的元素是自己new出来的,必须要先delete,否则会有内存泄漏

         如下实例:

#include <iostream>
#include <map>
#include <string>
#include <windows.h>
#include <stdio.h>

class Data
{
public:
    Data(std::string name) 
        :m_name{name} 
    {
        std::cout << "Data: " << m_name << std::endl;
        m_pData = new char[1024*1024];
    }
    virtual ~Data()
    {
        delete m_pData;
        m_pData = nullptr;
    }
private:
    std::string m_name = { "" };
    char* m_pData = nullptr;
};

std::map<std::string, Data*> gDataMap;

int eraseTest()
{
    std::cout << "eraseTest without delete" << std::endl;
    std::map<std::string, Data*>::iterator itor = gDataMap.begin();
    while (itor != gDataMap.end())
    {
        Data* pData = itor->second;
        if (pData != nullptr)
        {
            delete pData;
            pData = nullptr;
        }
        itor = gDataMap.erase(itor);
    }

    return 0;
}


int initMap()
{
    std::cout << "initMap" << std::endl;
    for (int i = 0; i < 100; i++)
    {
        std::string key = std::to_string(i);
        std::string name = "Data_" + std::to_string(i);
        Data* pData = new Data(name);
        gDataMap[key] = pData;
    }

    return 0;
}

int main()
{
    std::cout << "Hello World!\n";

    for (int i = 0; i < 1000; i++)
    {
		initMap();
		eraseTest();

        Sleep(100); //sleep for 100 mseconds
    }
    
    while (1)
    {
        ;
    }

    return 0;
}

  注释掉黄色部分,不手动delete,内存一会儿就爆了。

 

 加上黄色部分跑下来,正常回收

 

 

 

    4. map的key是否可以为类class或者struct,自定义呢,需要注意哪些

        答案是可以的, 如:std::map<std::string,std::string>

        自定义的也是可以的,但是:必须要重载运算符 <, 由于std::string已经重载,所以可以直接用

        

        https://blog.csdn.net/zhubaohua_bupt/article/details/62036499

        //看看map的定义

        template <class Key, class T, class Compare = less<Key>, class Alloc = alloc>

       各个参数:第一个key,第二个value,,第三个Compare是比较函数(小于),第四个是内存配置对象

        map内部存储机制实际是以红黑树为基础,红黑树在插入节点时,必须依照大小比对之后在一个合适的位置上执行插入动作。

       所以作为关键字,起码必须有“<”这个比较操作符。

        基础类型 int,float等等都有内置的比较函数,与map搭配无论是插入还是查找,都没什么问题。

        但是作为class或者struct,如果没有明确定义“<”比较操作符,就不能与map直接搭配使用,除非我们自己提供第三个参数compare函数

        因此:

        map的key需要满足以下两点:

         1.    “<”比较操作符,  自定义的类,需要重载运算符 <

         2.   如果没有“<”比较操作符,需要自定义第三个参数Compare,该仿函数实现“()”操作符,提供比较功能。插入时各节点顺序通过该仿函数来比较

 

posted on 2019-04-10 11:51  Leehm  阅读(1111)  评论(0编辑  收藏  举报