C++ std::move() vs std::memcpy()

Started by
13 comments, last by popsoftheyear 10 years ago

In adition to SiCrane's example, another thing that could complicate moving is pointers into the object itself. For example, a small vector might have a pointer that points within the object when there are few members, and to allocated memory when there are lots. That pointer would need to be updated to point within the moved object.

I understand that std::move(), std::memcpy(), and normal copying all copy bytes around. But in the context of C++ a move is different than a copy. So yes I am talking about std::memcpy(), but I'm talking about move semantics not copy semantics. POD types and std::is_trivially_copyable refer to copy semantics. For example a class like:

struct Object { 
   char* data; 
   Object () : data(new char[10]);
   virtual ~Object () { delete[] data; }
   };

is not trivially copyable (you'd have two objects pointing to the same data on the heap), but... is it trivially moveable? There are no exceptions thrown. The pointer will move properly with a std::memcpy(), as there will be still only one owner. As long as the src isn't destructed we don't have a data leak. Does the hidden v-table pointer get copied properly? Will something else get mangled?

I hope that makes my question clearer.

One of the things that a move constructor needs to do is leave the source object in a destructable state. So a just a memmove wouldn't be enough here.

Advertisement

The obvious example that comes to mind, is when the object contains a pointer to one of its other members. I have just been using production code that has exactly that.

The other thing you should not overlook is that memcpy-ing may do most of the job for some types, but it doesn't in itself suppress destruction of the object where the data came from, which you would need to also do to avoid double-deletion. std::move on the other hand, gets implemented to null out pointers from the source location as necessary, causing subsequent destruction to be safe.

"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

One situation where memcpy() won't work but std::move() will is when the object's constructors and destructor handle self-registration. For example, if it registers itself as part of the root set to a garbage collector by giving the garbage collector it's address. If you just copy the the memory without updating the root set for the GC, the GC will be trying to use the old memory location for its sweeps.

Didn't think of that one, thank-you.

In adition to SiCrane's example, another thing that could complicate moving is pointers into the object itself. For example, a small vector might have a pointer that points within the object when there are few members, and to allocated memory when there are lots. That pointer would need to be updated to point within the moved object.

Another good point.

I'm not sure if someone mentioned this, but a clear difference when your class allocates memory is that std::memcpy will not remove ownership from the original. So when your object dies, it will release the memory, but the object you copied will still hold a pointer to the released memory, causing a crash down the road. std::move, on the other hand, will release ownership from the original object (zeroing pointers, etc) so that it can be destroyed without affecting the state of the target object.

A move affects both the source and the destination, while a copy only affects the destination.

I'm not sure if someone mentioned this, but a clear difference when your class allocates memory is that std::memcpy will not remove ownership from the original. So when your object dies, it will release the memory, but the object you copied will still hold a pointer to the released memory, causing a crash down the road. std::move, on the other hand, will release ownership from the original object (zeroing pointers, etc) so that it can be destroyed without affecting the state of the target object.

A move affects both the source and the destination, while a copy only affects the destination.

Exactly.


struct Object {
char* data;
Object () : data(new char[10]);
virtual ~Object () { delete[] data; }
};
is not trivially copyable (you'd have two objects pointing to the same data on the heap), but... is it trivially moveable? There are no exceptions thrown. The pointer will move properly with a std::memcpy(), as there will be still only one owner. As long as the src isn't destructed we don't have a data leak. Does the hidden v-table pointer get copied properly? Will something else get mangled?

The pointer will NOT move properly. It gets copied properly. There are now 2 owners, not 1. You said "as long as src isn't destructed" but that's an important detail that highlights a major difference between memcpy and move.

This topic is closed to new replies.

Advertisement