This is a recycling of a reply I just made to Mingxin Wang and Gašper Ažman over at std-proposals. TLDR I think “trivially swappable” is a straightforward corollary to “trivially relocatable”, but its cost-of-specification might be a bit higher, and its benefit-in-performance is essentially zero as far as any use-case I can think of.
In my C++Now 2018 talk on “trivially relocatable” (which is fully captioned and I highly recommend you watch it!), I promised in the outline to talk about the relationship between “trivially relocatable” and “trivially swappable,” and then did not actually do so. Sorry! Let’s do that now.
Essentially, if a type is trivially relocatable then it intuitively ought to be considered trivially swappable. However, there are two minor caveats that I can think of off the top of my head (and the reason I didn’t talk about it at C++Now is that I haven’t thought about it much, and the reason for that is that I don’t have a motivating use-case).
Caveat (A): Trivial relocation can be optimized into
Trivial swap cannot be optimized into
mem-anything, because there is no libc primitive for
swapping arrays of bytes. We could certainly propose to add a
__builtin_memswap() that would
perform the swap “in-place” in cache-line-sized blocks, but I’m not aware of any proposals
nor prior art in that area.
Caveat (B): Notice that whereas “relocate” means “move-construct, then destroy”, we might say
that “swap” means “move-construct, then move-assign, then move-assign, then destroy.” (This
being the operation done by the unconstrained
std::swap template.) This involves a
relationship among 3 operations, which might be a little scarier than relocate’s relationship
among 2 operations, which is scarier than the current Standard Library’s “trivially X” traits
which all involve only a single operation.
Caveat (C): For small types like
__builtin_memswap() will not be any faster
than the unconstrained
std::swap template. The point of optimizing into
to get speedups on large arrays, such as during
std::vector swapping is already fast, and cannot be made faster by
std::array swapping could be made faster! Consider:
std::array<std::unique_ptr<int>, 10000> a; std::array<std::unique_ptr<int>, 10000> b; a.swap(b); // could probably get a factor-of-2 speedup on this operation by using __builtin_memswap
But this is not an operation that happens often enough in real programs for anyone to get really motivated about.
So, “trivially swappable” seems like a straightforward corollary to “trivially relocatable”, but its cost-of-specification might be a bit higher, and its benefit-in-performance is essentially zero as far as any use-case I can think of.