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

--- Comment #10 from Arthur O'Dwyer <arthur.j.odwyer at gmail dot com> ---
> Still better than duplicating the whole class IMO.

The `optional` example in P1144R0 Appendix B looks scarier than I should have.
For one thing, I omitted all the boring user-facing API of `optional` (emplace,
reset, has_value, operator bool, operator*, operator->, ...) which would be
implemented in the top level and thus shared by everyone. For another thing, I
showed the metaprogramming for BOTH trivially relocatable AND trivially
constructible/destructible in the same example. Adding trivial relocatability
to a library type doesn't involve any duplication of member function
implementations. It's tedious for sure, but mechanical.

Here's the commit where I trivially-relocatable-ized `std::deque`. 34 lines
added, 18 more lines changed. There's some duplication, but it's not literally
"duplicating the whole class."
https://github.com/llvm-mirror/libcxx/commit/cccc6d330fba37852455a3905b402b1aabe05474#diff-38adc80cec663f2f29c22e9ffc0de912


> I was looking into using relocation in std::swap. ... Maybe types that are 
> trivially relocatable but not trivially movable and destructible? Or just 
> non-trivial?

My commit for `std::swap` is here:
https://github.com/Quuxplusone/libcxx/commit/4d89aa95a7da86d1671d3e4441967782399fc3f9#diff-d436eb0fd9de10b54a828ce6435f7e81
It's extremely naive. I just say, if the type is_trivially_relocatable, then we
use memcpy --- EXCEPT, if the type is_empty, then we should NOT use memcpy,
because that is highly likely to break real code.
https://quuxplusone.github.io/blog/2018/07/13/trivially-copyable-corner-cases/

> For the array swap, I could use a large intermediate buffer on the side 
> (memcpy really shines on large regions), possibly as large as the full array, 
> but I would need to cap it to some safe size (hard to define).

A couple of people have mentioned to me that libc is conspicuously missing a
`memswap(void *a, void *b, size_t n)` primitive (such as would be used
internally by `qsort`). If libc guaranteed us an efficient implementation of
`memswap`, we wouldn't need to do so much micro-optimization at the C++ level.

> By the way, when swapping ranges of a type that does not specialize/overload 
> swap, it seems wasteful to call swap on each element, because it creates a 
> new temporary object for each element instead of reusing the same one.

I'm not sure I follow. Are you relying on the premise that move-constructing an
object, and then destructing a moved-from object, is more expensive than
move-assigning into a moved-from object? I would expect move-assigning to be
*no cheaper* than move-constructing, and so constructing and destructing a new
temporary for each element ought to be *no more expensive* (and possibly
cheaper) than reusing the same one.
But I have no actual benchmark numbers. Do you?

Re detecting overloads/specializations of std::swap, I think both are
impossible, but I'm curious what you're thinking of, BUT I bet it's off-topic
for this issue, so maybe you could email me your idea? :)

Reply via email to