C++17stladvanced
std::map::try_emplace / insert_or_assign
C++17 · Practical Modern · Compiler flag: -std=c++17
Explanation
`try_emplace` constructs a value in-place only if the key does not already exist, avoiding unnecessary construction and move operations. `insert_or_assign` inserts a new element or updates an existing one, always assigning the value regardless of whether the key was present.
Real-World Scenario
Maintain a user session cache where new sessions are created on first visit and existing sessions are updated on subsequent visits.
Quick Snippet
snippet.cpp
#include <map>
#include <string>
std::map<int, std::string> sessions;
// Only constructs the string if key 1 doesn't exist
sessions.try_emplace(1, "new_session_token");
// Inserts or updates -- always sets the value
sessions.insert_or_assign(1, "refreshed_token");Full Example
map_try_emplace.cpp
// CodeNebula - C++17 Example: std::map try_emplace and insert_or_assign
// Compile: g++ -std=c++17 -Wall -Wextra -o example map_try_emplace.cpp
// Demonstrates C++17 additions to std::map: try_emplace (inserts only if
// key doesn't exist, avoiding unnecessary moves) and insert_or_assign
// (inserts or overwrites, returning whether insertion occurred).
#include <iostream>
#include <map>
#include <string>
// A type that reports when it's constructed or moved
struct Value {
std::string data;
Value(const std::string& s) : data(s) {
std::cout << " Constructed: \"" << data << "\"" << std::endl;
}
Value(Value&& other) noexcept : data(std::move(other.data)) {
std::cout << " Moved: \"" << data << "\"" << std::endl;
}
Value& operator=(Value&& other) noexcept {
data = std::move(other.data);
std::cout << " Move-assigned: \"" << data << "\"" << std::endl;
return *this;
}
};
void print_map(const std::map<int, Value>& m) {
for (const auto& [k, v] : m) {
std::cout << " " << k << " -> \"" << v.data << "\"" << std::endl;
}
}
int main()
{
// ------------------------------------------------------------------
// 1. try_emplace: insert only if key absent
// ------------------------------------------------------------------
std::cout << "=== try_emplace ===" << std::endl;
std::map<int, Value> m;
std::cout << " Insert key 1:" << std::endl;
auto [it1, ok1] = m.try_emplace(1, "first");
std::cout << " inserted: " << ok1 << std::endl;
std::cout << " Try key 1 again:" << std::endl;
auto [it2, ok2] = m.try_emplace(1, "duplicate");
std::cout << " inserted: " << ok2 << std::endl;
std::cout << " value: \"" << it2->second.data << "\" (unchanged)" << std::endl;
// ------------------------------------------------------------------
// 2. try_emplace does NOT move arguments on failure
// ------------------------------------------------------------------
std::cout << "\n=== try_emplace Preserves Arguments ===" << std::endl;
std::string val = "preserved";
m.try_emplace(1, std::move(val)); // Key 1 exists; val NOT moved
std::cout << " val after failed try_emplace: \"" << val << "\"" << std::endl;
// ------------------------------------------------------------------
// 3. insert_or_assign: insert or overwrite
// ------------------------------------------------------------------
std::cout << "\n=== insert_or_assign ===" << std::endl;
std::map<int, std::string> scores;
auto [s1, ins1] = scores.insert_or_assign(1, "Alice");
std::cout << " Key 1 inserted: " << ins1 << " -> \"" << s1->second << "\"" << std::endl;
auto [s2, ins2] = scores.insert_or_assign(1, "Alice Updated");
std::cout << " Key 1 assigned: " << ins2 << " -> \"" << s2->second << "\"" << std::endl;
auto [s3, ins3] = scores.insert_or_assign(2, "Bob");
std::cout << " Key 2 inserted: " << ins3 << " -> \"" << s3->second << "\"" << std::endl;
// ------------------------------------------------------------------
// 4. try_emplace with hint (iterator position)
// ------------------------------------------------------------------
std::cout << "\n=== try_emplace with Hint ===" << std::endl;
std::map<int, std::string> config;
config[10] = "ten";
config[30] = "thirty";
// Hint: insert near the end
auto hint = config.end();
auto it = config.try_emplace(hint, 20, "twenty");
std::cout << " Inserted with hint: " << it->first << " -> " << it->second << std::endl;
std::cout << "\n Final map:" << std::endl;
for (const auto& [k, v] : config) {
std::cout << " " << k << " -> " << v << std::endl;
}
return 0;
}
/*
Expected output:
=== try_emplace ===
Insert key 1:
Constructed: "first"
inserted: 1
Try key 1 again:
inserted: 0
value: "first" (unchanged)
=== try_emplace Preserves Arguments ===
val after failed try_emplace: "preserved"
=== insert_or_assign ===
Key 1 inserted: 1 -> "Alice"
Key 1 assigned: 0 -> "Alice Updated"
Key 2 inserted: 1 -> "Bob"
=== try_emplace with Hint ===
Inserted with hint: 20 -> twenty
Final map:
10 -> ten
20 -> twenty
30 -> thirty
*/
Run command
g++ -std=c++17 -Wall -Wextra -o example map_try_emplace.cpp