https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121313

            Bug ID: 121313
           Summary: vector::insert_range causes self-move-assignment of
                    elements when given an empty range
           Product: gcc
           Version: 15.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: gulackeg at gmail dot com
  Target Milestone: ---

Test code:

    // https://godbolt.org/z/onoax95Ms

    #include <cassert>
    #include <ranges>
    #include <vector>

    struct S {
      S() = default;
      S(S &&) = default;
      S(const S &) = default;
      S &operator=(S &&other) {
        assert(&other != this);
        return *this;
      }
      S &operator=(const S &) = default;
    };

    int main() {
      std::vector<S> v(1);
      using namespace std::ranges;
      // libc++, MS STL: OK
      // libstdc++: Assertion `&other != this' failed
      v.insert_range(v.cbegin(), views::empty<S>);
      return 0;
    }


When given an empty range, libc++'s implementation of insert_range performs
unnecessary self-move-assignments for each element in the vector. This can be
problematic, as self-move-assignment is not guaranteed to be a no-op for
standard library types - it merely leaves the object in a valid but unspecified
state. A notable example is vector itself (its moved-from state is typically
being empty):

    // https://godbolt.org/z/av87xTqn7

    #include <cassert>
    #include <ranges>
    #include <vector>

    int main() {
      std::vector<std::vector<int>> v = {{42}};
      assert(v[0].size() == 1);
      using namespace std::ranges;
      v.insert_range(v.cbegin(), views::empty<std::vector<int>>);
      // libc++, MS STL: OK
      // libstdc++: Assertion `v[0].size() == 1' failed
      assert(v[0].size() == 1);
      return 0;
    }

Reply via email to