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

            Bug ID: 87749
           Summary: [6/7/8/9 Regression] std::__cxx11::basic_string move
                    assignment does deep copy unnecessarily
           Product: gcc
           Version: 9.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redi at gcc dot gnu.org
  Target Milestone: ---

#include <string>

bool oom = false;

template<typename T>
struct alloc
{
  using value_type = T;
  using size_type = unsigned long;
  using difference_type = long;
  using reference = T&;
  using const_reference = T&;
  using pointer = T*;
  using const_pointer = const T*;

  int not_empty = 0;

  template<typename U>
    struct rebind { using other = alloc<U>; };

  alloc() = default;
  template<typename U>
    alloc(const alloc<U>&) { }

  T* allocate(unsigned long n) {
    if (oom)
      throw std::bad_alloc();
    return std::allocator<T>().allocate(n);
  }

  void deallocate(T* p, unsigned long n) {
    std::allocator<T>().deallocate(p, n);
  }
};

template<typename T, typename U>
bool operator==(const alloc<T>&, const alloc<U>&) { return true; }
template<typename T, typename U>
bool operator!=(const alloc<T>&, const alloc<U>&) { return false; }

int main()
{
  using string = std::basic_string<char, std::char_traits<char>, alloc<char>>;

  string s = "a string that is longer than a short string";
  oom = true;
  string ss;
  ss = std::move(s);
}

The move assignment should transfer the allocated storage from s to ss, but
instead it does a deep copy, which throws here when an out-of-memory condition
is simulated.

The problem is that the move assignment operator only checks _S_always_equal
and if it's false doesn't do a runtime check for allocator equality.

I'm marking this as a regression, because prior to GCC 5 this code would not
fail when compiled with no options except -std=c++11. Since the default string
changed to the cxx11 one it fails (but still passes if the COW string is used).

Reply via email to