try_emplace向std::map实例中高效并有条件的插入元素

map是STL里重要容器之一。它的特性总结来讲就是:所有元素都会根据元素的键值key自动排序(也可根据自定义的仿函数进行自定义排序),其中的每个元素都是的键值对,map中不允许有键值相同的元素,因此map中元素的键值key不能修改,但是可以通过key修改与其对应的value。如果一定要修改与value对应的键值key,可将已存在的key删除掉,然后重新插入。cpp17 使用 extract

我们需要用键值对填充一个map实例时,会碰到两种不同的情况:

  1. 键不存在。创建一个全新的键值对。
  2. 键已存在。修改键所对应的值。

我通常会使用insertemplace函数对map插入新元素,如果插入不成功,那么就是第二种情况,就需要去修改现有的元素。
insertemplace都会创建一个新元素尝试插入到map实例中,不过在第二种情况下,这个新生成的元素会被丢弃。(如果键已存在,无法通过insert 和 emplace 插入成功),两种情况下,我们都会多调用一次构造函数。try_emplace也无法插入成功,只是不再尝试创建新元素,不再调用一次构造函数

map的元素键是唯一的,因此插入操作将检查每个插入的元素是否具有与容器中已有元素相同的键,如果是,则不插入该元素,并将迭代器返回给此现有元素,如果函数返回一个值。

#include 
#include 

using namespace std;


int main()
{
    cout << "---------------insert------------------"<<endl;
    map<int,string> m2;
    m2.insert({1,"111"});
    m2.insert({2,"222"});
    const auto [it1, success_1] = m2.insert({3,"333"});//pair insert ( const value_type& x ) | 在map中插入键值对x,注意x是一个键值对,返回值也是键值对
    cout << "insert 333 res: " << success_1 << endl; // insert 333 res: 1
    cout << (*it1).first << " " << (*it1).second << endl; //(*it1).first 3 , (*it1).second 333   插入成功返回插入元素迭代器, emplace同理 

    
    for (auto [k,v] : m2)
    {
        cout << "key: " << k << " value: " << v <<endl;
    }
    
    
    cout << "---------------------------------"<<endl;
    const auto [it2, success_2] = m2.insert({3,"666"});
    cout << "insert 666 res: " << success_2 << endl;// insert 666 res: 0 
    cout << (*it2).first << " " << (*it2).second << endl;// (*it2).first 3 , (*it2).second 333 插入失败返回当前元素迭代器,emplace同理 
    
    
    for (auto [k,v] : m2)
    {
        cout << "key: " << k << " value: " << v <<endl;
    }

}

std::map中的try_emplace函数展开,这个函数是C++17添加的。下面是其函数声明之一:

std::pair try_emplace(const key_type& k, Args&&... args);

其函数第一个参数k是插入的键,args表示这个键对应的值。如果我们成功的插入了元素,那么函数就会返回一个迭代器,其指向新节点在表中的位置,组对中布尔变量的值被置为true。当插入不成功,组对中的布尔变量值会置为false,并且迭代器指向与新元素冲突的位置

Note:

std::mapinsertemplace方法完全相同。try_emplace与它们不同的地方在于,在遇到已经存在的键时,不会去构造组对。当相应对象的类型需要很大开销进行构造时,这对于程序性能是帮助的。

C++17中,添加了try_emplace函数,其只有在满足条件的情况下,才能插入新元素。

#include 
#include 
using namespace std;


int main()
{
    cout << "---------------emplace------------------"<<endl;
    map<int,string> m1;
    m1.emplace(1,"111");
    m1.emplace(2,"222");
    m1.emplace(3,"333");
    for (auto [k,v] : m1)
    {
        cout << "key: " << k << " value: " << v <<endl;
    }
    cout << "---------------------------------"<<endl;
    m1.emplace(3,"666");

    for (auto [k,v] : m1)
    {
        cout << "key: " << k << " value: " << v <<endl;
    }
    
    cout << "---------------insert------------------"<<endl;
    map<int,string> m2;
    m2.insert({1,"111"});
    m2.insert({2,"222"});
    const auto [it1, success_1] = m2.insert({3,"333"});
    cout << "insert 333 res: " << success_1 << endl;
    for (auto [k,v] : m2)
    {
        cout << "key: " << k << " value: " << v <<endl;
    }
    cout << "---------------------------------"<<endl;
    const auto [it2, success_2] = m2.insert({3,"666"});
    cout << "insert 666 res: " << success_2 << endl;

    for (auto [k,v] : m2)
    {
        cout << "key: " << k << " value: " << v <<endl;
    }
  
    cout << "---------------try_emplace------------------"<<endl;
    map<int,string> m3;
    m3.try_emplace(1,"111");
    m3.try_emplace(2,"222");
    const auto [it3, success_3] = m3.insert({3,"333"});
    cout << "insert 333 res: " << success_1 << endl;
    for (auto [k,v] : m3)
    {
        cout << "key: " << k << " value: " << v <<endl;
    }
    cout << "---------------------------------"<<endl;
    const auto [it4, success_4] = m3.insert({3,"666"});
    cout << "insert 666 res: " << success_2 << endl;

    for (auto [k,v] : m3)
    {
        cout << "key: " << k << " value: " << v <<endl;
    }
    
}

try_emplace

#include 
#include 
#include 
 
#include 
 
auto print_node = [](const auto &node) {
    std::cout << "[" << node.first << "] = " << node.second << '\n';
};
 
auto print_result = [](auto const &pair) {
    std::cout << (pair.second ? "inserted: " : "ignored:  ");
    print_node(*pair.first);
};
 
int main()
{
    using namespace std::literals;
    std::map<std::string, std::string> m;
 
    print_result( m.try_emplace("a", "a"s) );
    print_result( m.try_emplace("b", "abcd") );
    print_result( m.try_emplace("c", 10, 'c') );
    print_result( m.try_emplace("c", "Won't be inserted") );
 
    for (const auto &p : m) { print_node(p); }
}

There’s more…

如果我们将表的类型从std::map换成std::unordered_map,程序照样能工作。这样的话,当不同类型的表具有较好的性能特性时,我们就可以快速的进行切换。

你可能感兴趣的:(cpp17,&,20,c++,算法,开发语言)