std::unorde...mplace_hint(3)
π std::unordered_set::emplace_hint(3) π
okay so this one's from the C++ Standard Libary manual (that's the manual's name bestie, i'm not making it up, it's on the tin) and it's about std::unordered_set::emplace_hint β say that five times fast, i dare you π
πΈ NAME πΈ
std::unordered_set::emplace_hint β std::unordered_set::emplace_hint
like yeah. the name is the name. it's giving "i contain myself" energy and honestly? iconic.
β¨ Synopsis β¨
template< class... Args >
iterator emplace_hint( const_iterator hint, Args&&... args );
(since C++11) β β yes queen, she's been here since 2011.
okay so the tea β: this bad girl inserts a new element into the container, and it takes hint as a suggestion for where the element should go. a suggestion, bestie. a vibe check. a lil nudge. not a demand π«Ά
the constructors of the key and mapped value get called with exactly the same arguments you handed to the function, forwarded with std::forward<Args>(args).... no cap, exactly the same ones.
and now the part where you need to actually pay attention π β if after the operation the new number of elements is greater than old max_load_factor() * bucket_count(), a rehashing takes place. and if rehashing occurs (because of the insertion), all iterators are invalidated. otherwise (no rehashing), iterators are not invalidated. that's the whole deal, fr fr. don't come crying to me when your iterator ghosted you π
π¦ Parameters π¦
hintβ an iterator, used as a suggestion as to where to insert the new element. only a suggestion!! she's flexible πargsβ the arguments you forward to the constructor of the element. all of them. every single one.
π Return value π
an iterator to the inserted element β or to the element that prevented the insertion. so either way you get an iterator back, you're never left on read π
π Exceptions π
if an exception is thrown for any reason, this function has no effect. that's the strong exception safety guarantee, and she EARNED that adjective π₯ strong exception safety guarantee. periodt.
β Complexity β
amortized constant on average, worst case linear in the size of the container. so like, usually a slay, occasionally a whole saga π«
π Example π
// Run this code
#include <chrono>
#include <cstddef>
#include <functional>
#include <iomanip>
#include <iostream>
#include <unordered_set>
const int n_operations = 100'500'0;
std::size_t set_emplace()
{
std::unordered_set<int> set;
for (int i = 0; i < n_operations; ++i)
set.emplace(i);
return set.size();
}
std::size_t set_emplace_hint()
{
std::unordered_set<int> set;
auto it = set.begin();
for (int i = 0; i < n_operations; ++i)
{
set.emplace_hint(it, i);
it = set.end();
}
return set.size();
}
std::size_t set_emplace_hint_wrong()
{
std::unordered_set<int> set;
auto it = set.begin();
for (int i = n_operations; i > 0; --i)
{
set.emplace_hint(it, i);
it = set.end();
}
return set.size();
}
std::size_t set_emplace_hint_corrected()
{
std::unordered_set<int> set;
auto it = set.begin();
for (int i = n_operations; i > 0; --i)
{
set.emplace_hint(it, i);
it = set.begin();
}
return set.size();
}
std::size_t set_emplace_hint_closest()
{
std::unordered_set<int> set;
auto it = set.begin();
for (int i = 0; i < n_operations; ++i)
it = set.emplace_hint(it, i);
return set.size();
}
double time_it(std::function<std::size_t()> set_test,
const char* what = nullptr,
double ratio = 0.0)
{
const auto start = std::chrono::system_clock::now();
const std::size_t setsize = set_test();
const auto stop = std::chrono::system_clock::now();
const std::chrono::duration<double, std::milli> time = stop - start;
if (what != nullptr && setsize > 0)
std::cout << std::setw(8) << time << " for " << what << " (ratio: "
<< (ratio == 0.0 ? 1.0 : ratio / time.count()) << ")\n";
return time.count();
}
int main()
{
std::cout << std::fixed << std::setprecision(2);
time_it(set_emplace); // cache warmup
const auto x = time_it(set_emplace, "plain emplace");
time_it(set_emplace_hint, "emplace with correct hint", x);
time_it(set_emplace_hint_wrong, "emplace with wrong hint", x);
time_it(set_emplace_hint_corrected, "corrected emplace", x);
time_it(set_emplace_hint_closest, "emplace using returned iterator", x);
}
π Possible output π
146.88ms for plain emplace (ratio: 1.00)
168.20ms for emplace with correct hint (ratio: 0.87)
168.78ms for emplace with wrong hint (ratio: 0.87)
166.58ms for corrected emplace (ratio: 0.88)
168.27ms for emplace using returned iterator (ratio: 0.87)
ngl theset_emplace_hintblock setsit = set.end()every single loop and the "corrected" version sets it toset.begin()β that's literally in the source, i'm not touching it, i just report the lore π
π See also π
emplaceβ constructs element in-place (public member function)insertβ inserts elements or nodes (since C++17) (public member function)
that's the whole page bestie, you ate that π no rehashing required. this lil number came from http://cppreference.com and it's dated 2024.06.10, so go hydrate and thank the nice people who wrote it π§β¨
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms