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; }