std::flat_map::operator[](3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

okay bestie, pull up a chair, because we're about to talk about std::flat_map::operator[] β€” yes, that one, the square-bracket girly who literally inserts stuff for you. this page comes straight out of the C++ Standard Libary docs (their spelling, not mine, keeping it πŸ’― accurate) and it's page std::flat_map::operator[](3) in the man pages. she's been iconic since C++23 and she has three whole overloads. let's get into it πŸŽ€

✨ NAME ✨

std::flat_map::operator[] β€” that's her. that's the whole name. short, sweet, main character energy πŸ‘‘


🌸 Synopsis 🌸

three flavours, all since C++23, all slaying:

T& operator[]( const Key& key ); (1) (since C++23)
T& operator[]( Key&& key );      (2) (since C++23)
template< class K >              (3) (since C++23)
T& operator[]( K&& x );

so what does she do? she hands you a reference to the value that is mapped to a key equivalent to key or x respectively β€” and if that key doesn't already exist? she performs an insertion. no cap, she just goes ahead and makes it πŸ’…

  1. (1) β€” Inserts a value_type object constructed in-place if the key does not exist. Equivalent to return try_emplace(x).first->second;.
  2. (2) β€” Inserts a value_type object constructed in-place if the key does not exist. Equivalent to return try_emplace(std::move(x)).first->second;.
  3. (3) β€” Inserts a value_type object constructed in-place if there is no key that transparently compares equivalent to the value x. Equivalent to return this->try_emplace(std::forward<K>(x)).first->second;. this overload participates in overload resolution only if the qualified-id Compare::is_transparent is valid and denotes a type. it lets you call this function without constructing an instance of Key, which is honestly so efficient of her πŸ¦‹
🫢 quick side quest: information on iterator invalidation is copied from here. that's it, that's the note β€” go look at here if you need the invalidation tea.

πŸ“ Parameters πŸ“

  • key β€” the key of the element to find πŸ”
  • x β€” a value of any type that can be transparently compared with a key ✨

πŸ’œ Return value πŸ’œ

  1. 1,2) β€” a reference to the mapped value of the new element if no element with key key existed. otherwise, a reference to the mapped value of the existing element whose key is equivalent to key.
  2. 3) β€” a reference to the mapped value of the new element if no element with key that compares equivalent to the value x existed. otherwise, a reference to the mapped value of the existing element whose key compares equivalent to x.

either way you get a T& back, so go wild πŸ’…


πŸ”₯ Exceptions πŸ”₯

if an exception is thrown by any operation, the insertion has no effect. she said no half-finished business, we don't do that here πŸ™ˆ


⭐ Complexity ⭐

Logarithmic in the size of the container, plus the cost of insertion (if any) of an empty element. so, you know, log n plus a lil extra snack πŸ“


πŸ¦‹ Notes πŸ¦‹

operator[] is non-const because it inserts the key if it doesn't exist. that's the whole reason, bestie, she's not being difficult, she's just doing her job.

if this behavior is undesirable, or if the container is const, at may be used instead β€” at is the chill one that won't sneak an insert on you 🧚

also insert_or_assign returns more information than operator[] and does not require default-constructibility of the mapped type. so if your mapped type can't be default-constructed, that's your girl πŸ‘‘


🌈 Example 🌈

// Run this code

#include <iostream>
#include <string>
#include <flat_map>

void println(auto const comment, auto const& map)
{
    std::cout << comment << '{';
    for (const auto& pair : map)
        std::cout << '{' << pair.first << ": " << pair.second << '}';
    std::cout << "}\n";
}

int main()
{
    std::flat_map<char, int> letter_counts{{'a', 27}, {'b', 3}, {'c',
       1}};

    println("letter_counts initially contains: ", letter_counts);

    letter_counts['b'] = 42; // updates an existing value
    letter_counts['x'] = 9;  // inserts a new value

    println("after modifications it contains: ", letter_counts);

    // count the number of occurrences of each word
    // (the first call to operator[] initialized the counter with zero)
    std::flat_map<std::string, int>  word_map;
    for (const auto& w : {"this", "sentence", "is", "not", "a",
"sentence",
                          "this", "sentence", "is", "a", "hoax"})
        ++word_map[w];
    word_map["that"]; // just inserts the pair {"that", 0}

    for (const auto& [word, count] : word_map)
        std::cout << count << " occurrence(s) of word '" << word <<
"'\n";
}

πŸ’– Output πŸ’–

letter_counts initially contains: {{a: 27}{b: 3}{c: 1}}
after modifications it contains: {{a: 27}{b: 42}{c: 1}{x: 9}}
2 occurrence(s) of word 'a'
1 occurrence(s) of word 'hoax'
2 occurrence(s) of word 'is'
1 occurrence(s) of word 'not'
3 occurrence(s) of word 'sentence'
0 occurrence(s) of word 'that'
2 occurrence(s) of word 'this'

the way word_map["that"]; just inserts {"that", 0} without you doing anything β€” and then the count prints as 0 β€” she ate that fr fr 😭πŸ”₯


🧚 See also 🧚

  • at β€” access specified element with bounds checking (public member function)
  • insert_or_assign β€” inserts an element or assigns to the current element if the key already exists (public member function)
  • try_emplace β€” inserts in-place if the key does not exist, does nothing if the key exists (public member function)

and that's the page, bestie 🫢 source is http://cppreference.com, dated 2024.06.10, filed under std::flat_map::operator[](3) β€” go forth and bracket responsibly πŸ’…βœ¨

πŸ“¦ where this page comes from