5

Suppose I have any kind of class or structure. No virtual functions or anything, just some custom constructors, as well as a few pointers that would require cleanup in the destructor.

Would there be any adverse affects to using memcpy or memmove on this structure? Will deleting a moved structure cause problems? The question assumes that the memory alignment is also correct, and we are copying to safe memory.

Serge
  • 1,974
  • 6
  • 21
  • 33

5 Answers5

9

In the general case, yes, there will be problems. Both memcpy and memmove are bitwise operations with no further semantics. That might not be sufficient to move the object*, and it is clearly not enough to copy.

In the case of the copy it will break as multiple objects will be referring to the same dynamically allocated memory, and more than one destructor will try to release it. Note that solutions like shared_ptr will not help here, as sharing ownership is part of the further semantics that memcpy/memmove don't offer.

For moving, and depending on the type you might get away with it in some cases. But it won't work if the objects hold pointers/references to the elements being moved (including self-references) as the pointers will be bitwise copied (again, no further semantics of copying/moving) and will refer to the old locations.

The general answer is still the same: don't.


* Don't take move here in the exact C++11 sense. I have seen an implementation of the standard library containers that used special tags to enable moving objects while growing buffers through the use of memcpy, but it required explicit annotations in the stored types that marked the objects as safely movable through memcpy, after the objects were placed in the new buffer the old buffer was discarded without calling any destructors (C++11 move requires leaving the object in a destructible state, which cannot be achieved through this hack)

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
5

Generally using memcpy on a class based object is not a good idea. The most likely problem would be copying a pointer and then deleting it. You should use a copy constructor or assignment operator instead.

TheSteve
  • 1,138
  • 6
  • 12
  • I agree with the sentiment that using `memcpy` is not a good idea. Re the "on an object", note that `memcpy` can only be used on objects. So it's a bit redundant. – Cheers and hth. - Alf Aug 27 '12 at 03:06
  • If you consider primitives to be objects, then yes that statement is true. – TheSteve Aug 27 '12 at 03:14
  • 1
    this question is about C++, and the C++ standard defines what `object` is -- there is no room for personal opinion. check it out. and *please don't use Java terminology (or whatever it is) in an answer to a C++ question*. – Cheers and hth. - Alf Aug 27 '12 at 03:34
  • For reference: 1.8 The C++ object model "An object is a region of storage." By primitives, I meant scalar variables which are actually objects by definition. I have edited the original post to express my original intent of class based objects. Although it would seem that, Wikipedia needs some editing as it says, "Objects are instances of classes created at runtime" – TheSteve Aug 27 '12 at 04:30
  • +1 for research. :-) well, it's not perfect yet, but nothing's prefect. class based objects include POD objects (like simple C `struct`); you probably meant non-POD objects. or corresponding more refined terminology for C++11. it gets complicated... – Cheers and hth. - Alf Aug 27 '12 at 04:59
4

No, don't do this.

If you memcpy a structure whose destructor deletes a pointer within itself, you'l wind up doing a double delete when the second instance of the structure is destroyed in whatever manner.

The C++ idiom is copy constructor for classes and std::copy or any of its friends for copying ranges/sequences/containers.

Mark B
  • 95,107
  • 10
  • 109
  • 188
4

If you are using C++11, you can use std::is_trivially_copyable to determine if an object can be copied or moved using memcpy or memmove. From the documentation:

Objects of trivially-copyable types are the only C++ objects that may be safely copied with std::memcpy or serialized to/from binary files with std::ofstream::write()/std::ifstream::read(). In general, a trivially copyable type is any type for which the underlying bytes can be copied to an array of char or unsigned char and into a new object of the same type, and the resulting object would have the same value as the original.

Many classes don't fit this description, and you must beware that classes can change. I would suggest that if you are going to use memcpy/memmove on C++ objects, that you somehow protect unwanted usage. For example, if you're implementing a container class, it's easy for the type that the container holds to be modified, such that it is no longer trivially copyable (eg. somebody adds a virtual function). You could do this with a static_assert:

template<typename T>
class MemcopyableArray
{
    static_assert(std::is_trivially_copyable<T>::value, "MemcopyableArray used with object type that is not trivially copyable.");
    // ...
};
MuertoExcobito
  • 9,741
  • 2
  • 37
  • 78
3

Aside from safety, which is the most important issue as the other answers have already pointed out, there may also be an issue of performance, especially for small objects.

Even for simple POD types, you may discover that doing proper initialization in the initializer list of your copy constructor (or assignments in the assignment operator depending on your usage) is actually faster than even an intrinsic version of memcpy. This may very well be due to memcpy's entry code which may check for word alignment, overlaps, buffer/memory access rights, etc.... In Visual C++ 10.0 and higher, to give you a specific example, you would be surprised by how much preamble code that tests various things executes before memcpy even begins its logical function.

Michael Goldshteyn
  • 71,784
  • 24
  • 131
  • 181
  • So did I, until I actually profiled it. It is very fast for largish objects, which is a very platform specific notion, but horrendously slow for say a <20 byte copy, at least on my platform when compared to just copying the bytes in a for loop. – Michael Goldshteyn Aug 27 '12 at 03:16
  • 1
    +1 for mentioning efficiency. it's all well and good to point out that efficiency should be third place or lower on the list of concerns, but the fact is, not just most beginners but most programmers (misguidedly) think of efficiency first and foremost. and then it really helps to have some correction of the usual incorrect ideas about what's efficient and what isn't. let me just add that if one chooses to use much time on efficiency concerns, then it's also a good idea to **measure**. which you also mention. :-) – Cheers and hth. - Alf Aug 27 '12 at 03:40
  • This is a great example of how the biggest enemy of performance is assumptions. No matter what you think you know, measurement is the only truth. – kylefinn Aug 18 '17 at 18:07