std::multimap::operator=(3)

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

πŸ’… std::multimap::operator=(3) β€” C++ Standard Library, bestie edition

okay so this is the std::multimap assignment operators, literally the "copy this whole vibe into that container" page 🫢 it lives in the C++ Standard Library and it's giving very much "how do I make one multimap become another one" energy. Buckle up.


✨ Synopsis ✨

multimap& operator=( const multimap& other );                   (1)
multimap& operator=( multimap&& other );                        (2) (since C++11) (until C++17)
multimap& operator=( multimap&& other )
    noexcept(/* see below */);                                  (2) (since C++17)
multimap& operator=( std::initializer_list<value_type> ilist ); (3) (since C++11)

the whole point, the entire reason this page exists: Replaces the contents of the container. periodt πŸ’…

  • (1) the copy assignment operator β€” swoops in and replaces your contents with a copy of the contents of other. classic.
    • but okay, here's the tea πŸ“ if std::allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value is true, then the allocator of *this is replaced by a copy of other's allocator. and if the allocator of *this after assignment would compare unequal to its old value, the old allocator is used to deallocate the memory, then the new allocator is used to allocate it before copying the elements (since C++11). otherwise, the memory owned by *this may be reused when possible. in any case β€” either way bestie β€” the elements originally belonging to *this may be either destroyed or replaced by element-wise copy-assignment. so don't be out here holding references like nothing's gonna change πŸ™ˆ
  • (2) the move assignment operator β€” replaces the contents with those of other using move semantics (i.e. the data in other is moved from other into this container). and other is left in a valid but unspecified state afterwards β€” she's not destroyed, she's just... going through something 😭
    • if std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value is true, the allocator of *this is replaced by a copy of that of other.
    • if it's false and the allocators of *this and other do not compare equal, *this cannot take ownership of the memory owned by other and must move-assign each element individually, allocating additional memory using its own allocator as needed. the sad slow path, we hate to see it πŸ’€
    • in any case, all elements originally belonging to *this are either destroyed or replaced by element-wise move-assignment.
  • (3) replaces the contents with those identified by initializer list ilist. cute, concise, iconic ✨

🌸 Parameters 🌸

  • other β€” another container to use as data source
  • ilist β€” initializer list to use as data source

πŸŽ€ Return value πŸŽ€

*this β€” she returns herself, main character energy πŸ‘‘

πŸ”₯ Complexity πŸ”₯

  1. Linear in the size of *this and other.
  2. Linear in the size of *this unless the allocators do not compare equal and do not propagate, in which case linear in the size of *this and other.
  3. O(NlogN) in general, where N is size() + ilist.size(). Linear if ilist is sorted with respect to value_comp(). (see, sorting pays off, who knew πŸ’–)

🌈 Exceptions 🌈

  • 1-3) May throw implementation-defined exceptions. (until C++17)
  • 1,3) May throw implementation-defined exceptions.
  • 2) noexcept specification: (since C++17)
noexcept(std::allocator_traits<Allocator>::is_always_equal::value
         && std::is_nothrow_move_assignable<Compare>::value)

πŸ¦‹ Notes πŸ¦‹

After container move assignment (overload (2)), unless element-wise move assignment is forced by incompatible allocators, references, pointers, and iterators (other than the end iterator) to other remain valid β€” but they refer to elements that are now in *this. like, they moved out but kept their address, it's giving long-distance relationship 🧚

The current standard makes this guarantee via the blanket statement in [container.reqmts]/67, and a more direct guarantee is under consideration via LWG issue 2321. (iykyk, standards drama πŸ’œ)

⭐ Example ⭐

The following code uses operator= to assign one std::multimap to another:

// Run this code

#include <initializer_list>
#include <iostream>
#include <iterator>
#include <map>
#include <utility>

void print(auto const comment, auto const& container)
{
    auto size = std::size(container);
    std::cout << comment << "{ ";
    for (auto const& [key, value] : container)
        std::cout << '{' << key << ',' << value << (--size ? "}, " : "} ");
    std::cout << "}\n";
}

int main()
{
    std::multimap<int, int> x{{1,1}, {2,2}, {3,3}}, y, z;
    const auto w = {std::pair<const int, int>{4,4}, {5,5}, {6,6}, {7,7}};

    std::cout << "Initially:\n";
    print("x = ", x);
    print("y = ", y);
    print("z = ", z);

    std::cout << "Copy assignment copies data from x to y:\n";
    y = x;
    print("x = ", x);
    print("y = ", y);

    std::cout << "Move assignment moves data from x to z, modifying both x and z:\n";
    z = std::move(x);
    print("x = ", x);
    print("z = ", z);

    std::cout << "Assignment of initializer_list w to z:\n";
    z = w;
    print("w = ", w);
    print("z = ", z);
}

πŸ’– Output πŸ’–

Initially:
x = { {1,1}, {2,2}, {3,3} }
y = { }
z = { }
Copy assignment copies data from x to y:
x = { {1,1}, {2,2}, {3,3} }
y = { {1,1}, {2,2}, {3,3} }
Move assignment moves data from x to z, modifying both x and z:
x = { }
z = { {1,1}, {2,2}, {3,3} }
Assignment of initializer_list w to z:
w = { {4,4}, {5,5}, {6,6}, {7,7} }
z = { {4,4}, {5,5}, {6,6}, {7,7} }

notice how x got absolutely emptied out by the move β€” she gave everything she had, no cap πŸ˜­πŸ’€

πŸ‘‘ See also πŸ‘‘

  • constructor β€” constructs the multimap (public member function)

πŸ’œ Category πŸ’œ

  • * conditionally noexcept

lowkey a warning before you go: the copy-assignment path can destroy or element-wise copy-assign the elements that were already in *this, and after a move those references/pointers/iterators still point at stuff β€” but the stuff now lives in *this. do not come for me if your iterator is confused, I warned you bestie 🫢

and that's the page, fr fr β€” sourced from http://cppreference.com, dated 2024.06.10, filed under std::multimap::operator=(3). slay, go assign some maps πŸ’…βœ¨πŸŽ€

πŸ“¦ where this page comes from