📅  最后修改于: 2023-12-03 14:59:49.724000             🧑  作者: Mango
C++17 引入了 std::try_emplace() 函数,用于向映射和无序映射(map, unordered_map)中插入元素。该函数在插入元素之前会检查映射中是否已存在指定的键值。如果键值已存在,则函数不会插入元素,而是将插入操作交给用户。这意味着我们可以使用 std::try_emplace() 在不覆盖现有值的情况下插入元素。
映射和无序映射都是 C++ 标准库中的关联容器。映射将元素存储为键值对,其中键是唯一的,而值可以重复。无序映射存储元素的方式与映射相同,区别在于无序映射中的元素不按照键的顺序存储,因此无序映射的访问时间是常数。
std::try_emplace() 函数的语法如下:
template< class... Args >
std::pair<iterator,bool> try_emplace( const key_type& key, Args&&... args );
template< class... Args >
std::pair<iterator,bool> try_emplace( key_type&& key, Args&&... args );
template< class... Args >
iterator try_emplace( const_iterator hint, const key_type& key, Args&&... args );
template< class... Args >
iterator try_emplace( const_iterator hint, key_type&& key, Args&&... args );
其中,第一个参数 key 是键值,Args 是可选的构造函数参数列表,iterator 是一个指向新插入元素的迭代器,bool 是一个指示插入是否成功的布尔值。
插入元素时,我们可以用 C++17 中的 std::try_emplace(),它的工作方式与 std::emplace() 类似,但是在插入之前会检查键值是否已经存在。如果键值不存在,则使用给定的参数创建新元素并将其插入映射。否则,函数不会插入元素,而是返回映射中现有元素的迭代器。
例如,我们可以使用 std::try_emplace() 插入一个新元素,如果该元素已经存在,则不插入:
#include <iostream>
#include <map>
int main() {
std::map<std::string, int> myMap {{"apple", 1}, {"banana", 2}, {"orange", 3}};
auto [it, inserted] = myMap.try_emplace("apple", 4); // 不会插入,因为 "apple" 已经存在
if (inserted) {
std::cout << "apple inserted!\n";
} else {
std::cout << "apple already exists with value " << it->second << '\n';
}
auto [newIt, newInserted] = myMap.try_emplace("pear", 5); // 插入成功
if (newInserted) {
std::cout << "pear inserted with value " << newIt->second << '\n';
} else {
std::cout << "pear already exists with value " << newIt->second << '\n';
}
return 0;
}
上面的示例中,我们首先构造了一个名为 myMap 的 std::map,它包含三个元素:apple、banana 和 orange。我们使用 std::try_emplace() 尝试向 myMap 中插入键为 "apple"、值为 4 的新元素。由于 "apple" 已经存在于 myMap 中,所以不会插入,而是返回现有元素的迭代器。接着,我们尝试插入键为 "pear"、值为 5 的元素,由于 "pear" 不在 myMap 中,插入操作成功。
std::try_emplace() 还具有一个特殊的用法,即用新值更新现有元素的值。我们可以使用 std::try_emplace() 的键值参数以及元素值的构造函数参数来创建一个新元素。如果键值已经存在,则该元素的值将更新为新值。这使得我们可以轻松地实现插入或更新函数。
#include <iostream>
#include <map>
template <typename Map, typename KeyType, typename ValueType>
void insertOrOverwrite(Map& map, const KeyType& key, ValueType&& value) {
map.insert_or_assign(key, std::forward<ValueType>(value));
}
template <typename Map, typename KeyType, typename... Args>
void tryInsertOrUpdate(Map& map, const KeyType& key, Args&&... args) {
auto [it, inserted] = map.try_emplace(key, std::forward<Args>(args)...);
if (!inserted) {
it->second = std::forward<Args>(args)...;
}
}
int main() {
std::map<std::string, int> myMap {{"apple", 1}, {"banana", 2}, {"orange", 3}};
tryInsertOrUpdate(myMap, "pear", 4); // 插入 pear
tryInsertOrUpdate(myMap, "orange", 5); // 更新 orange
for (const auto& [key, value] : myMap) {
std::cout << key << ": " << value << '\n';
}
return 0;
}
在上面的示例中,我们定义了两个插入或更新函数。insertOrOverwrite() 函数将插入键和值,如果键已经存在,则元素值将被覆盖。tryInsertOrUpdate() 函数利用 std::try_emplace() 和解构绑定来进行插入或更新,如果键已经存在,则将现有元素的值替换为新的值。
在示例中,我们首先构造了一个名为 myMap 的 std::map,它包含三个元素:apple、banana 和 orange。然后,我们使用 tryInsertOrUpdate() 函数向 myMap 中插入或更新两个元素。最后,我们遍历 myMap 并输出所有元素的键和值。
std::try_emplace() 函数是 C++17 标准库中一个有用的功能,它使得向映射和无序映射中插入元素更加便捷。该函数返回一个迭代器和一个布尔值,在插入元素之前检查键是否已经存在,如果不存在,则创建一个新的元素。因此,我们可以使用 std::try_emplace() 来实现插入或更新函数。