https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79254
Jonathan Wakely <redi at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Known to work| |4.9.4 Version|unknown |5.4.1 Summary|basic_string::operator= |[5/6/7 Regression] |isn't exception safe |basic_string::operator= | |isn't exception safe Known to fail| |5.4.0, 6.3.0, 7.0 --- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> --- If we use a C++03-compatible allocator this variation on the testcase shows it's a regression compared to the old COW string, which didn't have this problem (partly because it doesn't support allocator propagation): #include <string> #include <stdio.h> int counter = 0; template <typename T> struct alloc : std::allocator<T> { using value_type = T; using propagate_on_container_copy_assignment = std::true_type; template<typename U> struct rebind { typedef alloc<U> other; }; alloc(int id = 0) : id(id) { } template <typename U> alloc(const alloc<U>& other) : id(other.id) { } T* allocate(std::size_t n) { if (++counter == 3) throw 1; return std::allocator<T>::allocate(n); } int id; }; template <typename T, typename U> bool operator==(const alloc<T>& lhs, const alloc<U>& rhs) { return lhs.id == rhs.id; } template <typename T, typename U> bool operator!=(const alloc<T>& lhs, const alloc<U>& rhs) { return lhs.id != rhs.id; } int main() { using broken_string = std::basic_string<char, std::char_traits<char>, alloc<char>>; broken_string s1("This is my first string", alloc<char>(1)); broken_string s2("This is my second string", alloc<char>(2)); s2.c_str(); // Prevent the string being shared, forcing a copy. try { s1 = s2; } catch (int) { puts("Caught exception."); } printf("s1 = %s\n", s1.c_str()); printf("s2 = %s\n", s2.c_str()); }