当前位置: 首页 > news >正文

<1> c++ 笔记 stl::map

目录

优先查看官网 cppreference.com

map 种类

1.  插入,添加元素

1.1 insert

1.2 emplace添加 (c++11)

2.0 批量拷贝,拼合

3.0 访问

3.1 at 访问

3.2 下标访问

 4. 查找

4.1迭代器查找

4.2 contains查找 (c++20)

4.3 count查找

5. 删除

6. 遍历

7. 析构

testDemo:

 8. emplace 和 insert


优先查看官网 cppreference.com

map笔记
这里只是记录常用方法,以及部分理解,方便自己查阅。以下demo皆以默认的c++11 标准

map 种类

std::map为有序的,以key作为排序。 一对一的关系,一个key只一个元素,插入新的会覆盖之前
std::unordered_map :也可以使用std::unordered_map,不会排序。
std::mutimap 和 std::unordered_mutimap. 可以一对多,运行key重复。

1.  插入,添加元素

1.1 insert

std::map 将会有序插入
mDogs.insert(std::pair<std::string, std::shared_ptr<Dog>>(dog1->name(), dog1));

1.2 emplace添加 (c++11)

emplace 的意思是 安放,不至于再出现一次从元素原来的值在生存一个拷贝,将拷贝insert到容器的情况。
https://zh.cppreference.com/w/cpp/container/map/emplace

mDogs.emplace(std::make_pair(dog3->name(), dog3));

2.0 批量拷贝,拼合

mDogs2.insert(mDogs.begin(), mDogs.end());

3.0 访问

3.1 at 访问

如果没有元素,会抛出异常。

try

{

std::cout << "at 访问konglong" << std::endl;

mDogs.at("konglong")->talk();

}

catch (const std::exception &e)

{

std::cerr << "at 异常:no konglong find, " << e.what() << '\n'

<< '\n';

}

3.2 下标访问

如果不存在就会自动添加一个元素,不推荐使用

auto dog = mDogs["konglong"];

if (dog != nullptr)

{

dog->talk();

}

else

{

std::cout << "下标访问不存在的元素导致自动添加空数据!" << std::endl

<< std::endl;

}

 4. 查找

        map中,contian() 和 count() 内部都是使用迭代器find 的查找方式实现的。 mutimap的count()有所不同。
         两外使用 std::find() 和std::find_if()  都不是map自身提供的方法,它是算法库里面提供的一种通用的泛形遍历查找的方法,本质上是一个通用的遍历比较函数

4.1迭代器查找

std::map<std::string, std::shared_ptr<Dog>>::iterator it = mDogs.find("dahuang");

if (it != mDogs.end())

{

std::cout << "find查找: " << it->second->name() << std::endl

<< std::endl;

}

4.2 contains查找 (c++20)

// 需要 c++20才支持

#if __cplusplus > 201703L //需要c++20 才支持 编译的时候加上:g++ -std=c++20

std::cout << "contains 查找:" << std::endl;

if (mDogs.contains("dahuang"))

{

mDogs["dahuang"]->talk();

}

std::cout << std::endl;

#endif

4.3 count查找

if (mDogs.count("dahuang") != 0)

{

mDogs["dahuang"]->talk();

}

5. 删除

mDogs.erase("dahuang");

6. 遍历

推荐使用for 范围遍历:

for (auto &dog : dogs)

{ // 6.0 for 范围 for循环 c++11 起支持。//https://zh.cppreference.com/w/cpp/language/range-for

// 如果要修改元素,用auto &

// 否则也可以用 auto

if (dog.second != nullptr)

dog.second->talk();

else

std::cout << "a died dog: " << dog.first << std::endl;

}

7. 析构

         要不要手动遍历逐个删除?要不要自己clear?
        不需要。 元素自身会被删除。

// 析构函数只会删除元素,(编译器的工作)。如果元素是裸指针,被程序员赋予了一个内存,那就需要程序员自己去释放这个内存。(程序员自己的工作)

// 本篇这里用的是智能指针对象,元素具有在被删除的时候自动释放内存的能力,OK。

// #if __cplusplus >= 201103L

// /**

// * The dtor only erases the elements, and note that if the elements

// * themselves are pointers, the pointed-to memory is not touched in any

// * way. Managing the pointer is the user's responsibility.

// */

// ~map() = default;

// #endif

       

析构demo
 

#include <map>
#include <iostream>
#include <string>
class Dog
{
public:
    Dog(std::string name, int color) : mName(name), mColor(color), bCopy(false)
    {
        std::cout << "new dog:" << mName << std::endl;
    }

    Dog(const Dog &dog) : mName(dog.mName + "_copy"), mColor(dog.mColor), bCopy(true)
    {

        std::cout << " 拷贝的dog :" << mName << std::endl;
    }

    ~Dog()
    {
        std::cout << mName << " died!!" << std::endl;
    }

private:
    std::string mName;
    int mColor = 0;
    bool bCopy = false;
};

int main()
{
    {
        std::map<int, Dog *> dogs1;
        dogs1.emplace(std::make_pair(1, new Dog("dahang1", 1)));
        dogs1.emplace(std::make_pair(2, new Dog("xiaohei1", 2)));
        //野指针。 Dog没有被释放
        std::cout<<"map1 即将析构"<<std::endl;
    }
    std::cout<<"map1 已经析构"<<std::endl<<std::endl;

    {
        std::map<int, Dog> dogs2;
        dogs2.insert(std::make_pair(1,Dog("dahuang2",1)));
        dogs2.insert(std::make_pair(2,Dog("xiaohei2",2)));
        std::cout<<"map2 即将析构-----"<<std::endl;
    }
    std::cout<<"map2 已经析构------"<<std::endl;
    

    return 0;
}

可以看到,普通的指针不会被析构(dogs1.emplace(std::make_pair(1, new Dog("dahang1", 1))); 在c++中几乎没有这种写法,只有java才比较常用),而存储的对象,会被析构,而智能指针其本质也是一个对象,就会被析构。

testDemo:

#include <string>
#include <memory>
#include <iostream>
#include <map>
#include <unordered_map>

class Dog
{
public:
    Dog(std::string name, int color) : mName(name), mColor(color)
    {
    }

    ~Dog()
    {
        std::cout << mName << " died!!" << std::endl;
    }
    void talk()
    {
        std::cout << mName << " ::wang wang" << std::endl;
    }
    std::string name()
    {
        return mName;
    }

private:
    std::string mName;
    int mColor = 0;
};
int main(int argc, const char *argv[])
{

    {
        std::map<std::string, std::shared_ptr<Dog>> mDogs;
        std::unordered_map<std::string, std::shared_ptr<Dog>> mDogs2;

        auto dogsTalk = [=](std::map<std::string, std::shared_ptr<Dog>> dogs)
        {
            std::cout << "<<<<---------" << std::endl;
            for (auto &dog : dogs)
            {
                if (dog.second != nullptr)
                    dog.second->talk();
                else
                    std::cout << "a died dog:" << dog.first << std::endl;
            }
            std::cout << "--------->>>" << std::endl;
            std::cout << std::endl;
        };

        auto dogsTalk2 = [=](std::unordered_map<std::string, std::shared_ptr<Dog>> dogs)
        {
            std::cout << "<<<---------" << std::endl;
            for (auto &dog : dogs)
            { // 6.0 for 范围 for循环 c++11 起支持。//https://zh.cppreference.com/w/cpp/language/range-for
                // 如果要修改元素,用auto &
                // 否则也可以用 auto
                if (dog.second != nullptr)
                    dog.second->talk();
                else
                    std::cout << "a died dog: " << dog.first << std::endl;
            }
            std::cout << "--------->>>" << std::endl;
            std::cout << std::endl;
        };

        { //
            std::shared_ptr<Dog> dog1 = std::make_shared<Dog>("dahuang", 2);
            std::shared_ptr<Dog> dog2 = std::make_shared<Dog>("xiaohei", 3);
            std::shared_ptr<Dog> dog3 = std::make_shared<Dog>("laobai", 4);

            // 1.0  插入
            mDogs.insert(std::pair<std::string, std::shared_ptr<Dog>>(dog1->name(), dog1));
            mDogs.insert(std::pair<std::string, std::shared_ptr<Dog>>(dog2->name(), dog2));

            // 1.1 emplace添加
            // emplace 的意思是 安放,不至于再出现一次从元素原来的值在生存一个拷贝,将拷贝insert到容器的情况。
            // https://zh.cppreference.com/w/cpp/container/map/emplace
            mDogs.emplace(std::make_pair(dog3->name(), dog3));

            std::cout << "插入完成,mDogs:" << std::endl;
            dogsTalk(mDogs);

            // 2.0 批量拷贝,拼合
            mDogs2.insert(mDogs.begin(), mDogs.end());
            std::cout << "拷贝完成,mDogs2:" << std::endl;
            dogsTalk2(mDogs2);

            // 3.0 at 访问
            try
            {
                std::cout << "at 访问konglong" << std::endl;
                mDogs.at("konglong")->talk();
            }
            catch (const std::exception &e)
            {
                std::cerr << "at 异常:no konglong find, " << e.what() << '\n'
                          << '\n';
            }

            // 3.1 下标访问,如果不存在就会自动添加一个元素,不推荐使用
            std::cout << "下标访问存在的元素:" << std::endl;
            mDogs["dahuang"]->talk();
            auto dog = mDogs["konglong"];
            if (dog != nullptr)
            {
                dog->talk();
            }
            else
            {
                std::cout << "下标访问不存在的元素导致自动添加空数据!" << std::endl
                          << std::endl;
            }

            // 4.0 查找
            std::map<std::string, std::shared_ptr<Dog>>::iterator it = mDogs.find("dahuang");
            if (it != mDogs.end())
            {
                std::cout << "find查找: " << it->second->name() << std::endl
                          << std::endl;
            }
            // 4.1 contains查找
#if __cplusplus > 201703L //需要c++20 才支持 编译的时候加上:g++ -std=c++20
            std::cout << "contains 查找:" << std::endl;
            if (mDogs.contains("dahuang"))
            {
                mDogs["dahuang"]->talk();
            }
            std::cout << std::endl;
#endif

            // 4.2 count查找
            std::cout << "count 查找" << std::endl;
            if (mDogs.count("dahuang") != 0)
            {
                mDogs["dahuang"]->talk();
            }
            std::cout << std::endl;

#if __cplusplus > 201103L
// 如果是 multimaps (支持一个key对应多个 value)
//  c++11 以上 有 auto count
#endif

            // 5.0 删除
            mDogs.erase("dahuang");
            std::cout << "删除之后:" << std::endl;
            dogsTalk(mDogs);

            std::cout << "元素创建括号即将结束" << std::endl;
        }
        std::cout << "元素创建括号结束" << std::endl
                  << std::endl;
        std::cout << "map创建括号即将结束,map即将被销毁" << std::endl;
    }
    // 析构函数只会删除元素,(编译器的工作)。如果元素是裸指针,被程序员赋予了一个内存,那就需要程序员自己去释放这个内存。(程序员自己的工作)
    // 本篇这里用的是智能指针对象,元素具有在被删除的时候自动释放内存的能力,OK。
    //     #if __cplusplus >= 201103L
    //       /**
    //        *  The dtor only erases the elements, and note that if the elements
    //        *  themselves are pointers, the pointed-to memory is not touched in any
    //        *  way.  Managing the pointer is the user's responsibility.
    //        */
    //       ~map() = default;
    //      #endif

    std::cout << "map创建括号结束,map已经被销毁" << std::endl;
}

g++ -std=c++20 stl_map.cpp


 

 8. emplace 和 insert

         实际测试发现,只是在 如下情况下,emplace才有比insert少一次拷贝构造的情况。
 

dogs2.emplace(3,Dog("laobai2",3));//只被拷贝一次

dogs2.insert(std::make_pair(4,Dog("ahuang",4)));//拷贝两次

// dogs2.insert(4,Dog("ahuang",4)); // 编译错误

测试demo:
 

#include <map>
#include <iostream>
#include <string>
class Dog
{
public:
    Dog(std::string name, int color) : mName(name), mColor(color), bCopy(false)
    {
        std::cout << "new dog:" << mName << std::endl;
    }

    //实现一个拷贝构造函数,让被拷贝的dog对象,name加上一个后缀。
    Dog(const Dog &dog) : mName(dog.mName + "_copy"), mColor(dog.mColor), bCopy(true)
    {

        std::cout << " 拷贝的dog :" << mName << std::endl;
    }

    ~Dog()
    {
        std::cout << mName << " died!!" << std::endl;
    }

private:
    std::string mName;
    int mColor = 0;
    bool bCopy = false;
};

int main()
{
#if 1
    {
        std::map<int, Dog> dogs2;

        {
            Dog d("dahuang2", 1);
            dogs2.emplace(std::make_pair(1, d)); // 拷贝两次。这里被拷贝复制。 为什么emplace 还拷贝?make_pair拷贝一次,emplace又拷贝一次。
            std::cout << "empalce 添加 dahuang2" << std::endl;
        }
        {
            dogs2.emplace(std::make_pair(2, Dog("xiaohei2", 2)));
            std::cout << "empalce 添加 xiaohei2" << std::endl;
        }

        dogs2.emplace(3, Dog("laobai2", 3)); //只被拷贝一次

        dogs2.insert(std::make_pair(4, Dog("ahuang", 4))); //拷贝两次
        // dogs2.insert(4,Dog("ahuang",4)); // 编译错误

        // dogs2.emplace(4,"cuihua",4); // 编译错误
        // dogs2.emplace(4,("cuihua",4)); // 编译错误
        std::cout << "map 即将销毁" << std::endl;
    }
#endif

    return 0;
}

 可以看到:

  • dogs2.emplace(std::make_pair(2, Dog("xiaohei2", 2)));// 拷贝两次。make_pair拷贝一次生成pair,emplace又拷贝一次放到map
  • dogs2.emplace(3, Dog("laobai2", 3)); //只被拷贝一次
  • dogs2.insert(std::make_pair(4, Dog("ahuang", 4))); // 拷贝两次

相关文章:

  • 怎样才算精通 Excel?超详细讲解!
  • 3.3Docker网络模式与资源控制
  • 【元宇宙欧米说】一个科幻 NFT,一场关于创作者经济的探索
  • 3.1虚拟化和安装Docker
  • 讲价 数学问题
  • Qt官方示例学习目录
  • 【下班神器】python写自动关机程序并打包成exe文件
  • SQL 改写系列十:半连接转内连接
  • 根据上下级关系统计数据
  • 金仓数据库KingbaseES客户端编程开发框架-Hibernate Spatial(2. 概述)
  • 第二十三章 多线程(一)
  • mysql的常见的外键约束
  • React基础-JSX语法介绍
  • SAP ABAP代码自动生成demo
  • 【JS】JavaScript入门笔记第七弹之JS简单类型与复杂类型~
  • 【Leetcode】101. 对称二叉树
  • -------------------- 第二讲-------- 第一节------在此给出链表的基本操作
  • .pyc 想到的一些问题
  • 【翻译】babel对TC39装饰器草案的实现
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • DataBase in Android
  • ECS应用管理最佳实践
  • Github访问慢解决办法
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • Javascript编码规范
  • Node 版本管理
  • 聊聊spring cloud的LoadBalancerAutoConfiguration
  • 每天一个设计模式之命令模式
  • 日剧·日综资源集合(建议收藏)
  • 如何实现 font-size 的响应式
  • 设计模式 开闭原则
  • CMake 入门1/5:基于阿里云 ECS搭建体验环境
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • $forceUpdate()函数
  • (11)工业界推荐系统-小红书推荐场景及内部实践【粗排三塔模型】
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (三)uboot源码分析
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (一)Spring Cloud 直击微服务作用、架构应用、hystrix降级
  • (一)SpringBoot3---尚硅谷总结
  • (转)用.Net的File控件上传文件的解决方案
  • .FileZilla的使用和主动模式被动模式介绍
  • .NET Remoting学习笔记(三)信道
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • @ComponentScan比较
  • @manytomany 保存后数据被删除_[Windows] 数据恢复软件RStudio v8.14.179675 便携特别版...
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [C++核心编程](四):类和对象——封装
  • [emuch.net]MatrixComputations(7-12)
  • [E链表] lc83. 删除排序链表中的重复元素(单链表+模拟)