• <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>(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>::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
     

    1. #include
    2. #include
    3. #include
    4. class Dog
    5. {
    6. public:
    7. Dog(std::string name, int color) : mName(name), mColor(color), bCopy(false)
    8. {
    9. std::cout << "new dog:" << mName << std::endl;
    10. }
    11. Dog(const Dog &dog) : mName(dog.mName + "_copy"), mColor(dog.mColor), bCopy(true)
    12. {
    13. std::cout << " 拷贝的dog :" << mName << std::endl;
    14. }
    15. ~Dog()
    16. {
    17. std::cout << mName << " died!!" << std::endl;
    18. }
    19. private:
    20. std::string mName;
    21. int mColor = 0;
    22. bool bCopy = false;
    23. };
    24. int main()
    25. {
    26. {
    27. std::map<int, Dog *> dogs1;
    28. dogs1.emplace(std::make_pair(1, new Dog("dahang1", 1)));
    29. dogs1.emplace(std::make_pair(2, new Dog("xiaohei1", 2)));
    30. //野指针。 Dog没有被释放
    31. std::cout<<"map1 即将析构"<
    32. }
    33. std::cout<<"map1 已经析构"<
    34. {
    35. std::map<int, Dog> dogs2;
    36. dogs2.insert(std::make_pair(1,Dog("dahuang2",1)));
    37. dogs2.insert(std::make_pair(2,Dog("xiaohei2",2)));
    38. std::cout<<"map2 即将析构-----"<
    39. }
    40. std::cout<<"map2 已经析构------"<
    41. return 0;
    42. }

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

    testDemo:

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. class Dog
    7. {
    8. public:
    9. Dog(std::string name, int color) : mName(name), mColor(color)
    10. {
    11. }
    12. ~Dog()
    13. {
    14. std::cout << mName << " died!!" << std::endl;
    15. }
    16. void talk()
    17. {
    18. std::cout << mName << " ::wang wang" << std::endl;
    19. }
    20. std::string name()
    21. {
    22. return mName;
    23. }
    24. private:
    25. std::string mName;
    26. int mColor = 0;
    27. };
    28. int main(int argc, const char *argv[])
    29. {
    30. {
    31. std::map> mDogs;
    32. std::unordered_map> mDogs2;
    33. auto dogsTalk = [=](std::map> dogs)
    34. {
    35. std::cout << "<<<<---------" << std::endl;
    36. for (auto &dog : dogs)
    37. {
    38. if (dog.second != nullptr)
    39. dog.second->talk();
    40. else
    41. std::cout << "a died dog:" << dog.first << std::endl;
    42. }
    43. std::cout << "--------->>>" << std::endl;
    44. std::cout << std::endl;
    45. };
    46. auto dogsTalk2 = [=](std::unordered_map> dogs)
    47. {
    48. std::cout << "<<<---------" << std::endl;
    49. for (auto &dog : dogs)
    50. { // 6.0 for 范围 for循环 c++11 起支持。//https://zh.cppreference.com/w/cpp/language/range-for
    51. // 如果要修改元素,用auto &
    52. // 否则也可以用 auto
    53. if (dog.second != nullptr)
    54. dog.second->talk();
    55. else
    56. std::cout << "a died dog: " << dog.first << std::endl;
    57. }
    58. std::cout << "--------->>>" << std::endl;
    59. std::cout << std::endl;
    60. };
    61. { //
    62. std::shared_ptr dog1 = std::make_shared("dahuang", 2);
    63. std::shared_ptr dog2 = std::make_shared("xiaohei", 3);
    64. std::shared_ptr dog3 = std::make_shared("laobai", 4);
    65. // 1.0 插入
    66. mDogs.insert(std::pair>(dog1->name(), dog1));
    67. mDogs.insert(std::pair>(dog2->name(), dog2));
    68. // 1.1 emplace添加
    69. // emplace 的意思是 安放,不至于再出现一次从元素原来的值在生存一个拷贝,将拷贝insert到容器的情况。
    70. // https://zh.cppreference.com/w/cpp/container/map/emplace
    71. mDogs.emplace(std::make_pair(dog3->name(), dog3));
    72. std::cout << "插入完成,mDogs:" << std::endl;
    73. dogsTalk(mDogs);
    74. // 2.0 批量拷贝,拼合
    75. mDogs2.insert(mDogs.begin(), mDogs.end());
    76. std::cout << "拷贝完成,mDogs2:" << std::endl;
    77. dogsTalk2(mDogs2);
    78. // 3.0 at 访问
    79. try
    80. {
    81. std::cout << "at 访问konglong" << std::endl;
    82. mDogs.at("konglong")->talk();
    83. }
    84. catch (const std::exception &e)
    85. {
    86. std::cerr << "at 异常:no konglong find, " << e.what() << '\n'
    87. << '\n';
    88. }
    89. // 3.1 下标访问,如果不存在就会自动添加一个元素,不推荐使用
    90. std::cout << "下标访问存在的元素:" << std::endl;
    91. mDogs["dahuang"]->talk();
    92. auto dog = mDogs["konglong"];
    93. if (dog != nullptr)
    94. {
    95. dog->talk();
    96. }
    97. else
    98. {
    99. std::cout << "下标访问不存在的元素导致自动添加空数据!" << std::endl
    100. << std::endl;
    101. }
    102. // 4.0 查找
    103. std::map>::iterator it = mDogs.find("dahuang");
    104. if (it != mDogs.end())
    105. {
    106. std::cout << "find查找: " << it->second->name() << std::endl
    107. << std::endl;
    108. }
    109. // 4.1 contains查找
    110. #if __cplusplus > 201703L //需要c++20 才支持 编译的时候加上:g++ -std=c++20
    111. std::cout << "contains 查找:" << std::endl;
    112. if (mDogs.contains("dahuang"))
    113. {
    114. mDogs["dahuang"]->talk();
    115. }
    116. std::cout << std::endl;
    117. #endif
    118. // 4.2 count查找
    119. std::cout << "count 查找" << std::endl;
    120. if (mDogs.count("dahuang") != 0)
    121. {
    122. mDogs["dahuang"]->talk();
    123. }
    124. std::cout << std::endl;
    125. #if __cplusplus > 201103L
    126. // 如果是 multimaps (支持一个key对应多个 value)
    127. // c++11 以上 有 auto count
    128. #endif
    129. // 5.0 删除
    130. mDogs.erase("dahuang");
    131. std::cout << "删除之后:" << std::endl;
    132. dogsTalk(mDogs);
    133. std::cout << "元素创建括号即将结束" << std::endl;
    134. }
    135. std::cout << "元素创建括号结束" << std::endl
    136. << std::endl;
    137. std::cout << "map创建括号即将结束,map即将被销毁" << std::endl;
    138. }
    139. // 析构函数只会删除元素,(编译器的工作)。如果元素是裸指针,被程序员赋予了一个内存,那就需要程序员自己去释放这个内存。(程序员自己的工作)
    140. // 本篇这里用的是智能指针对象,元素具有在被删除的时候自动释放内存的能力,OK。
    141. // #if __cplusplus >= 201103L
    142. // /**
    143. // * The dtor only erases the elements, and note that if the elements
    144. // * themselves are pointers, the pointed-to memory is not touched in any
    145. // * way. Managing the pointer is the user's responsibility.
    146. // */
    147. // ~map() = default;
    148. // #endif
    149. std::cout << "map创建括号结束,map已经被销毁" << std::endl;
    150. }

    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:
     

    1. #include
    2. #include
    3. #include
    4. class Dog
    5. {
    6. public:
    7. Dog(std::string name, int color) : mName(name), mColor(color), bCopy(false)
    8. {
    9. std::cout << "new dog:" << mName << std::endl;
    10. }
    11. //实现一个拷贝构造函数,让被拷贝的dog对象,name加上一个后缀。
    12. Dog(const Dog &dog) : mName(dog.mName + "_copy"), mColor(dog.mColor), bCopy(true)
    13. {
    14. std::cout << " 拷贝的dog :" << mName << std::endl;
    15. }
    16. ~Dog()
    17. {
    18. std::cout << mName << " died!!" << std::endl;
    19. }
    20. private:
    21. std::string mName;
    22. int mColor = 0;
    23. bool bCopy = false;
    24. };
    25. int main()
    26. {
    27. #if 1
    28. {
    29. std::map<int, Dog> dogs2;
    30. {
    31. Dog d("dahuang2", 1);
    32. dogs2.emplace(std::make_pair(1, d)); // 拷贝两次。这里被拷贝复制。 为什么emplace 还拷贝?make_pair拷贝一次,emplace又拷贝一次。
    33. std::cout << "empalce 添加 dahuang2" << std::endl;
    34. }
    35. {
    36. dogs2.emplace(std::make_pair(2, Dog("xiaohei2", 2)));
    37. std::cout << "empalce 添加 xiaohei2" << std::endl;
    38. }
    39. dogs2.emplace(3, Dog("laobai2", 3)); //只被拷贝一次
    40. dogs2.insert(std::make_pair(4, Dog("ahuang", 4))); //拷贝两次
    41. // dogs2.insert(4,Dog("ahuang",4)); // 编译错误
    42. // dogs2.emplace(4,"cuihua",4); // 编译错误
    43. // dogs2.emplace(4,("cuihua",4)); // 编译错误
    44. std::cout << "map 即将销毁" << std::endl;
    45. }
    46. #endif
    47. return 0;
    48. }

     可以看到:

    • 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))); // 拷贝两次

  • 相关阅读:
    索引的数据结构、索引及其优缺点、索引的声明与使用以及索引的设计原则
    GaussDB新特性Ustore存储引擎介绍
    怎么把pdf压缩的小一点?
    Visual Studio 2023年下载、安装教程、亲测有效
    亿级流量高并发春晚互动前端技术揭秘
    Android入门第34天-Android的Menu组件使用大全
    【数据分析】基于Matlab的Critic和修正Critic得到权重结果
    【LeetCode】移除盒子 [H](记忆化搜索)
    MySQL增删改查(基础)
    KdMapper扩展实现之REALiX(hwinfo64a.sys)
  • 原文地址:https://blog.csdn.net/u012459903/article/details/126869845