Safely moving a C ++ object

Ive heard some warnings about moving an object to another memory location via memcpy , but I don’t know the specific reasons. If its contained members do not have complex things that depend on the location of the memory, it should be absolutely safe ... or not?

EDIT: The intended use case is a data structure, such as a vector , that stores objects (not pointers to objects) in a contiguous portion of memory (i.e. an array). To insert a new object at the nth position, all objects starting at position n and above must be moved to make room for the object.

+4
source share
7 answers

For discussion purposes, I assume that you mean the transition to the fact that the original object was "discarded" (no longer used, did not execute its destructor), and did not have two copies (which would lead to a much bigger problem, reference counting, and etc.). I usually refer to the property of being able to do this bitwise.

In the basics of the code I'm working on, most objects are bit-wise movable, since they do not store independent links. However, some data structures are not bitwise (I believe gcc std :: set was not bitwise, other examples would be linked list nodes ). In general, I would avoid trying to use this property, since this can lead to very difficult debugging of errors and prefer object-oriented calls to copy constructors.

Edited to add :

There seems to be some confusion about how / why someone did this: here is a comment I made about how:

Usually, I see the above implementations of the vector. Memory is allocated through malloc (sizeof (Class) * size) and objects are built in place through explicitly called constructors and destructors. Sometimes (for example, during redistribution), they must be moved, so the std :: vector option re-calls copy constructors to new memory and destructors to old ones, or use memcopy and just “free” the old block. In most cases, the latter simply “works,” but not for all objects.

In this regard, the memcopy (or realloc ) approach can be significantly faster.

Yes, it causes undefined behavior, but it also just works for most objects. Some people think speed is worth it. If you were really configured to use this approach, I would suggest implementing a bitwise_movable property of the type to allow types that work for the white list and return to the traditional copy for objects that are not in the white list, similar to the example here .

+3
source

One of the main reasons why you shouldn't do this is destructors. When you memcpy a C ++ object to another location in memory, you will get 2 versions of the object in memory for which only one constructor was run. This will destroy the resource release logic in almost every C ++ class.

+6
source

This is not allowed by the language specification. This behavior is undefined. That is, ultimately, what is wrong with him. In practice, it tends to mess with virtual function calls, which means that the destructor will execute twice (and more often than constructors), member objects are not deeply copied (so if, for example, if you try this trick with std::vector , it explodes as several objects fall into the same internal array.)

The exception is POD types. They don’t (copy) constructors, destructors, virtual functions, base classes or anything else that could cause it to break, so you can use memcpy to copy them with them.

+4
source

If the object did not have pointers inside it and there are no virtual functions, there are no children with any of them, you can deal with it. This is not recommended !!!

This should be done using the copy function or deep copy or overridden statements.

In the method, you call the new constructor and copy its data elements in turn.

for a shallow copy, you should copy pointers / links so that you have two objects pointing to the same elements contained ... a potential memory leak nightmare.

for a deep copy, you will move the contained objects and links, creating new copies of them.

To move an object, you must copy it and delete the original.

+2
source

Short answer: std::memcpy() is for moving memory, not for moving objects. However, using this method will cause undefined behavior.

A slightly longer answer: a C ++ object that is not a POD may contain resources that need to be freed up and that are stored in pens that cannot be easily copied. (A popular resource is memory, where the descriptor is a pointer.) It can also contain material inserted by the implementation (pointers to an instance of a virtual base class) that should not be copied as if it were memory.

The only sure way to move an object in C ++ 98 and C ++ 03 is to copy it to a new location and call the destructor in the old one. (In C ++ 1x there will be semantics of movement, so in some cases the situation may become more interesting.)

+2
source

Above my head: if you just make memcpy, you will end up making a shallow copy. If you need a deep copy, this will not work.

What is wrong with copy constructor and assignment operators?

+1
source

In general (and in all languages, not just C ++), to safely move an object, you also need to rewrite ALL pointers / links to this object to indicate a new location. This is a problem in C ++ because there is no easy way to tell if any object in the system has a “hidden” pointer to the object you are moving. As you noticed, some classes may contain hidden pointers to themselves. Other classes may have hidden pointers in a factory object that keeps track of all instances. It is also possible for seemingly unrelated classes to cache pointers to objects for various reasons.

The only way to do this safely is if you have some kind of reflective access to all the objects in the system so that you can find all the pointers to the object and rewrite them. This is potentially a very expensive operation anyway, so the systems that need it (for example, copying garbage collectors) are usually very carefully organized to copy multiple objects at once and / or link the places that need to be looked for pointers with write barriers and etc.

0
source

All Articles