[Bug libstdc++/110138] Extra constructor called when using basic_string::operator+
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110138 --- Comment #6 from Jonathan Wakely --- What matters is the "value" of the allocator, not how many times it gets copied.
[Bug libstdc++/110138] Extra constructor called when using basic_string::operator+
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110138 --- Comment #5 from Jonathan Wakely --- Just use a stateful allocator and check that the correct state is propagated. See testsuite/21_strings/basic_string/allocator/char/operator_plus.cc which does exactly that.
[Bug libstdc++/110138] Extra constructor called when using basic_string::operator+
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110138 Hongyu Wang changed: What|Removed |Added Resolution|--- |INVALID Status|UNCONFIRMED |RESOLVED --- Comment #4 from Hongyu Wang --- (In reply to Jonathan Wakely from comment #3) > (In reply to Hongyu Wang from comment #0) > > GCC 12.3/Clang 16 outputs: > > Alloc: 3 > > Alloc: 6 > > Alloc: 9 > > Alloc: 12 > > "Clang 16" here actually means "Any version of Clang with libstdc++ headers > from GCC 12". > > The figures for Clang's own libc++ are different: > > Alloc: 0 > Alloc: 4 > Alloc: 8 > Alloc: 12 > > But again, this is meaningless. Nobody cares how many times an allocator is > copied. The original test intends to verify P1165R1 implementation and it uses a global counter on allocator constructor to see if it is correctly selected, and current change makes it copied twice so the result is not expected. But yes, I agree the allocator constructor for string should be cheap, and the original test should not rely on how many times the constructor was called to verify P1165R1 (I suppose checks if soccc was called instead). Thanks for the explanation, I will close this as invalid.
[Bug libstdc++/110138] Extra constructor called when using basic_string::operator+
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110138 --- Comment #3 from Jonathan Wakely --- (In reply to Hongyu Wang from comment #0) > GCC 12.3/Clang 16 outputs: > Alloc: 3 > Alloc: 6 > Alloc: 9 > Alloc: 12 "Clang 16" here actually means "Any version of Clang with libstdc++ headers from GCC 12". The figures for Clang's own libc++ are different: Alloc: 0 Alloc: 4 Alloc: 8 Alloc: 12 But again, this is meaningless. Nobody cares how many times an allocator is copied.
[Bug libstdc++/110138] Extra constructor called when using basic_string::operator+
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110138 --- Comment #2 from Jonathan Wakely --- Why do you care how many times an allocator is copied? They should be cheap (essentially free) to copy. A far more interesting test would look at how many bytes are allocated for string concatenation: #include #include int n_ = 0; int b_ = 0; void alloc_cnt() { std::cout<< "Allocators: " << n_ << ", bytes: " << b_ << '\n'; } template struct myAlloc_ : std:: allocator { myAlloc_() { } myAlloc_(myAlloc_&& r) { ++n_; } myAlloc_(const myAlloc_& r) { ++n_; } myAlloc_& operator=(const myAlloc_& other) { return *this; } T* allocate(std::size_t n) { T* ptr = std::allocator::allocate(n); b_ += n * sizeof(T); return ptr; } template struct rebind { typedef myAlloc_ other; }; }; using mystring = std:: basic_string, myAlloc_>; int main() { mystring f_ = "abc0", b_ = "def", c_ = "xyz"; alloc_cnt (); auto a = f_ + "mno" + b_; alloc_cnt (); auto c = c_ + f_ + b_; alloc_cnt (); auto d = c_ + (f_ + b_); alloc_cnt (); return 0; } With GCC 12: Allocators: 3, bytes: 21 Allocators: 6, bytes: 83 Allocators: 9, bytes: 114 Allocators: 12, bytes: 176 With GCC 13: Allocators: 3, bytes: 21 Allocators: 7, bytes: 52 Allocators: 11, bytes: 83 Allocators: 15, bytes: 114 The program uses less memory to achieve the same result. This was changed by r13-3814-gc93baa93df2d45 and is actually important. The number of copies of allocators is a meaningless figure.
[Bug libstdc++/110138] Extra constructor called when using basic_string::operator+
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110138 --- Comment #1 from Hongyu Wang --- operator+ now calls std::__cxx11::basic_string, myAlloc_ >::get_allocator, and it will call the constructor again after gimplify __attribute__((nodiscard)) struct allocator_type std::__cxx11::basic_string, myAlloc_ >::get_allocator ( const struct basic_string * const this) { try { _1 = std::__cxx11::basic_string, myAlloc_ >::_M_get_allocator (this); myAlloc_::myAlloc_ (, _1); return ; } catch { <<>> } __builtin_unreachable trap (); } Possibly caused by r13-3814-gc93baa93df2d45