Practical advantages of std::copy, std::equal, std::fill over memcpy, memset, memcmp

363 Views Asked by At

A few posts compare the performance between C++-style functions std::copy, std::equal, std::fill with C-style functions std::memcpy, std::memcmp, std::memset, for example :

But I haven't found what justifies the replacement by these new functions over the old one from a practical point of view. Of course, the list of functions is not exhaustive.

What are the practical advantages of these new versions ?

If performance is not a criterion for choosing, is it desirable (time permitting) to replace all occurrences of these C-style functions with the C++ versions ?

I tried to understand why some functions have been introduced in c++ and if it is necessary to do the replacement.

3

There are 3 best solutions below

1
On BEST ANSWER

But I haven't found what justifies the replacement by these new functions over the old one from a practical point of view.

These functions are more general. memcpy and memset are only defined for contiguous ranges of types that are TriviallyCopyable, and memcmp is (generally) only meaningful for contiguous ranges of TriviallyCopyable types with no padding. N.b. a single object is vacuously a contiguous range of length one.

Performance is only comparable when they do the same things, and by the as-if rule, an implementation can choose to implement a call to std::copy in exactly the same way as it does memcpy when it can prove the ranges don't overlap, or memmove otherwise. Similarly std::fill with memset and std::equal with memcmp1.

  1. slightly modified, because it doesn't care about less or greater, just equal
2
On

memset has two drastic limitations.

First the container. You can only memset more than a single element to a container that uses contiguous memory. It can work for std::array or std::vector but not for most other containers.

Next, the elements. You can only memset trivially copyable objects. Already something as "simple" as std::string is not trivially copyable.

memset can be used in some cases. The other functions you mention are more generally applicable and when they can be replaced by memset the compiler can do that.

6
On

As has been pointed out in the comments, std::copy, etc. work, where as std::memcpy, ect. only work in a very limited number of cases. In particular, std::memcpy doesn't work for anything with an non-trivial constructor, so for none of the standard containers. Even when used on a C style struct, or a C style array of structs, it only does a shallow copy, so depending on the semantics of the object, it may not work even on a C style struct which contains a pointer.

With regards to performance, nothing is of course guaranteed. But the compiler will have access to the source of std::copy (because it is a template), and will typically be able to inline it -- for C style structs, this would usually result in copying in larger chunks (machine words, rather than bytes). In the case of std::memcpy, there is typically a function call, which hides any information about the underlying context, and requires either a byte-wise copy (resulting a lot more times in the loop), or complicated logic for handling alignment and a possible odd number of bytes. The C standard does allow memcpy to be a macro, resolving to a special symbol which triggers some sort of compiler optimization, but I don't think this is legal in C++. And some earlier, pre-(C)standard C compilers did recognize memcpy as if it were a keyword, in order to generate inline code. But this is all in the very distant past (before the first C standard).

In today's C++ code, there is absolutely no reason to use std::memcpy, ever.