On Sun, Jul 8, 2018 at 6:40 PM, Marc Glisse <marc.gli...@inria.fr> wrote:
> On Fri, 6 Jul 2018, Martin Sebor wrote:
>> On 07/05/2018 05:14 PM, Soul Studios wrote:
>>>
>>> Simply because a struct has a constructor does not mean it isn't a
>>> viable target/source for use with memcpy/memmove/memset.
>>
>>
>> As the documentation that Segher quoted explains, it does
>> mean exactly that.
>>
>> Some classes have user-defined copy and default ctors with
>> the same effect as memcpy/memset.  In modern C++ those ctors
>> should be defaulted (= default) and GCC should emit optimal
>> code for them.
>
> What if I want to memcpy a std::pair<int,int>?

That's fine, since the pair copy constructor is defaulted, and trivial
for pair<int,int>.

> Some classes may have several states, some that are memcpy-safe, and some
> that are not. A user may know that at some point in their program, all the
> objects in a given array are safe, and want to memcpy the whole array
> somewhere.

The user may know that, but the language only defines the semantics of
memcpy for trivially copyable classes.  If you want to assume that the
compiler will do what you expect with this instance of undefined
behavior, you can turn off the warning.  You may well be right, but I
don't think it follows that putting this warning about undefined
behavior in -Wall is wrong.

> memcpy can also be used to work around the lack of a destructive move in
> C++.

I wonder what you mean by "the lack of a destructive move in C++",
given that much of C++11 was about supporting destructive move
semantics.

> For instance, vector<vector<T>>::resize could safely use memcpy (and
> skip destroy before deallocate). In this particular case, we could imagine
> at some point in the future that the compiler would notice it is equivalent
> to memcpy+bzero, and then that the bzero is dead, but there are more
> complicated use cases for destructive move.

Indeed, resizing a vector<vector<T>> will loop over the outer vector
calling the move constructor for each inner vector, which will copy
the pointer and zero out the moved-from object, which the optimizer
could then coalesce into memcpy/bzero.  This sort of pattern is common
enough in C++11 containers that this seems like an attractive
optimization, if we don't already perform it.

What more complicated uses don't reduce to memcpy/bzero, but you would
still want to use memcpy for somehow?

>> In fact, in loops they can result in more
>> efficient code than the equivalent memset/memcpy calls.  In
>> any case, "native" operations lend themselves more readily
>> to code analysis than raw memory accesses and as a result
>> allow all compilers (not just GCC) do a better a job of
>> detecting bugs or performing interesting transformations
>> that they may not be able to do otherwise.
>>
>>> Having benchmarked the alternatives memcpy/memmove/memset definitely
>>> makes a difference in various scenarios.
>>
>> Please open bugs with small test cases showing
>> the inefficiencies so the optimizers can be improved.
>
> Some already exist (PR 86024 seems related, there are probably some closer
> matches), but indeed more would be helpful.

86024 does seem relevant to the vector resize example.

Jason

Reply via email to