std::set::set(3)

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

πŸ’– std::set::set(3) β€” C++ Standard Libary πŸ’–

okay bestie, this is std::set::set(3) from the C++ Standard Libary (yes, the manual name is spelled like that up top, and we're keeping it because details are sacred πŸ’…). It's literally the constructor page for std::set, and it's giving β€œbuild a container from any source” main-character energy. 🫢

🌸 NAME 🌸

std::set::set β€” bestie, it's the std::set constructor, so the name is literally std::set::set. no cap. ✨

✨ Synopsis ✨

okay so here's the whole overload family, and yes, every C++ version tag is staying because we don't erase lore:

          set();
       (until C++11)
          set()
       (since C++11)
              : set(Compare()) {}
          explicit set( const Compare& comp,                                (2)
                        const Allocator& alloc = Allocator() );
          explicit set( const Allocator& alloc );                           (3)
       (since C++11)
          template< class InputIt >

          set( InputIt first, InputIt last,                                 (4)
               const Compare& comp = Compare(),

               const Allocator& alloc = Allocator() );
          template< class InputIt >

          set( InputIt first, InputIt last,                                 (5)
       (since C++14)
               const Allocator& alloc )

              : set(first, last, Compare(), alloc) {}
          set( const set& other );                                          (6)
          set( const set& other, const Allocator& alloc );                  (7)
       (since C++11)
          set( set&& other );                                               (8)
       (since C++11)
          set( set&& other, const Allocator& alloc );                       (9)
       (since C++11)
          set( std::initializer_list<value_type> init,                  (1)

               const Compare& comp = Compare(),
       (10) (since C++11)

               const Allocator& alloc = Allocator() );
          set( std::initializer_list<value_type> init,

               const Allocator& alloc )
       (11) (since C++14)

              : set(init, Compare(), alloc) {}
          template< container-compatible-range<value_type> R >

          set( std::from_range_t, R&& rg,
       (12) (since C++23)
               const Compare& comp = Compare(),

               const Allocator& alloc = Allocator() );
          template< container-compatible-range<value_type> R >

          set( std::from_range_t, R&& rg,
               const Allocator& alloc )
       (13) (since C++23)

              : set(std::from_range, std::forward<R>(rg), Compare(),
          alloc) {}

okay so the whole vibe: this constructor makes a new container from a bunch of different data sources, and it can optionally use a user-supplied allocator alloc or comparison function object comp. it's giving β€œchoose your own adventure” but for container initialization. πŸ’«

  • 1–3) constructs an empty container. iconic. nothing in it yet.
  • 4,5) constructs the container with the contents of the range [first, last). If multiple elements in the range have keys that compare equivalent, it is unspecified which element is inserted (pending LWG2844). If [first, last) is not a valid range, the behavior is undefined β€” that's a hard no, bestie. 😭
  • 6,7) copy constructor. constructs the container with a copy of the contents of other. If alloc is not provided, the allocator is obtained by calling (since C++11) std::allocator_traits<allocator_type>::select_on_container_copy_construction(other.get_allocator()). During class template argument deduction, only the first argument contributes (since C++23) to the deduction of the container's Allocator template parameter. πŸŽ€
  • 8,9) move constructor. constructs the container with the contents of other using move semantics. If alloc is not provided, the allocator is obtained by move-construction from the allocator belonging to other. During class template argument deduction, only the first argument contributes to the deduction of the container's Allocator template parameter (since C++23). πŸ’¨
  • 10,11) initializer-list constructor. constructs the container with the contents of the initializer list init. If multiple elements in the range have keys that compare equivalent, it is unspecified which element is inserted (pending LWG2844). πŸ“
  • 12,13) constructs the container with the contents of rg. If multiple elements in the range have keys that compare equivalent, it is unspecified which element is inserted (pending LWG2844). 🌈

πŸ’œ Parameters πŸ’œ

  • alloc β€” allocator to use for all memory allocations of this container.
  • comp β€” comparison function object to use for all comparisons of keys.
  • first, last β€” the range to copy the elements from.
  • other β€” another container to be used as source to initialize the elements of the container with.
  • init β€” initializer list to initialize the elements of the container with.
  • rg β€” a container compatible range, that is, an input_range whose elements are convertible to value_type.

πŸ¦‹ Type requirements πŸ¦‹

  • InputIt must meet the requirements of LegacyInputIterator.
  • Compare must meet the requirements of Compare.
  • Allocator must meet the requirements of Allocator.

πŸ”₯ Complexity πŸ”₯

  • 1–3) constant.
  • 4,5) NΒ·log(N) where N is std::distance(first, last) in general, and linear in N if [first, last) is already sorted by value_comp().
  • 6,7) linear in size of other.
  • 8,9) constant. If alloc is given and alloc != other.get_allocator(), then linear.
  • 10,11) NΒ·log(N) where N is init.size() in general, and linear in N if init is already sorted by value_comp().
  • 12,13) NΒ·log(N) where N is ranges::distance(rg) in general, and linear in N if rg is already sorted by value_comp().

πŸ’€ Exceptions πŸ’€

Calls to Allocator::allocate may throw. that's it. that's the warning. πŸ’…

🧚 Notes 🧚

After container move construction (overloads (8,9)), references, pointers, and iterators (other than the end iterator) to other remain valid, but they refer to elements that are now in *this. 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. 🫢

Although not formally required until C++23, some implementations has already put the template parameter Allocator into non-deduced contexts in earlier modes.

Feature-test macro glow-up:

  • __cpp_lib_containers_ranges = 202202L (C++23): Ranges-aware construction and insertion; overloads (12,13).

🌟 Example 🌟

okay bestie, // Run this code and watch it cook: πŸ”₯

        #include <cmath>
        #include <iostream>
        #include <set>
        #include <string>

        struct Point { double x, y; };

        struct PointCmp
        {
            bool operator()(const Point& lhs, const Point& rhs) const
            {
                return std::hypot(lhs.x, lhs.y) < std::hypot(rhs.x, rhs.y);
            }
        };

        std::ostream& operator<<(std::ostream& os, Point pt)
        {
            return os << '(' << pt.x << ',' << pt.x << ')';
        }

        void println(auto rem, const auto& seq)
        {
            std::cout << rem << '{';
            for (auto n{seq.size()}; const auto& elm : seq)
                std::cout << elm << (--n ? ", " : "");
            std::cout << "}\n";
        }

        int main()
        {
            // (1) Default constructor
            std::set<std::string> a;
            a.insert("horse");
            a.insert("cat");
            a.insert("dog");
            println("1) a: ", a);

            // (4) Range constructor
            std::set<std::string> b(a.find("dog"), a.end());
            println("2) b: ", b);

            // (6) Copy constructor
            std::set<std::string> c(a);
            c.insert("another horse");
            println("3) c: ", c);

            // (8) Move constructor
            std::set<std::string> d(std::move(a));
            println("4) d: ", d);
            println("5) a: ", a);

            // (10) Initializer list constructor
            std::set<std::string> e{"one", "two", "three", "five", "eight"};
            println("6) e: ", e);

            // Custom comparison
            std::set<Point, PointCmp> f = {{2, 5}, {3, 4}, {1, 1}};
            f.insert({1, -1}); // This fails because the magnitude of (1,-1)
       equals (1,1)
            println("7) f: ", f);

            // (12) Range constructor
            const auto w = {"Eurybia", "Theia", "Rhea", "Aura", "Mnemosyne",
       "Mnemosyne"};
        #if __cpp_lib_containers_ranges
            std::set<std::string> g(std::from_range, w); // overload (12)
        #else
            std::set<std::string> g(w.begin(), w.end()); // fallback to (4)
        #endif
            println("8) g: ", g);
        }

🌈 Possible output 🌈

        1) a: {cat, dog, horse}
        2) b: {dog, horse}
        3) c: {another horse, cat, dog, horse}
        4) d: {cat, dog, horse}
        5) a: {}
        6) e: {eight, five, one, three, two}
        7) f: {(1,1), (3,3), (2,2)}
        8) g: {Aura, Eurybia, Mnemosyne, Rhea, Theia}

πŸŽ€ Defect reports πŸŽ€

The following behavior-changing defect reports were applied retroactively to previously published C++ standards. (yes, retroactively. the lore goes back. ⏳)

  • LWG 2076, applied to C++11: overload (4) conditionally required Key to be CopyInsertable into *this; correct behavior: not required.
  • LWG 2193, applied to C++11: the default constructor was explicit; correct behavior: made non-explicit.

🌸 See also 🌸

  • operator= β€” assigns values to the container (public member function).

mwah πŸ’‹ this page came from http://cppreference.com, version 2024.06.10, for std::set::set(3). stay hydrated and may your allocators always behave. 🫢✨

πŸ“¦ where this page comes from