The above layout is trivial among other things because the above Capsule instance contains all of its data. Basically, it has no pointers to elsewhere. It is one self-contained memory block.
That is important for swap or move. Basically, the compiler is swapping memory blocks when dealing with standard layout.
1
2
3
capsuleA=create(false);
capsuleB=create(true);
std::swap(A,B);
The above is indeed swapped. The compiler can do this (on its own) because each instance above is in its own memory block; the situation is laid out as two memory blocks.
Quick recap. Here is the visualization of the swap( A, B ) operation. Two values swapping.
Values swapping
Please note: Temporary is local to the swap function. Again, please remember: By C++ standard, B value is moved from. And left in this curious “undefined” state. Do not use it as it is moved from.
That’s it. Done. Let’s go out and have some fun?! Well … not yet. What comes is:
Native Pointers are not Fundamental Types
I will ask again: you are clear on the C++ type system right? In particular, you are now sure where do native pointers fit in. Good, but why does this matter now?
std::move applied to values has full effect. But, after the move operation native pointers are left as they are. Pointers are:
Not fundamental types
Just memory addresses
std::move on a native pointer has no effect.
What exactly happens if you move from the pointer?
1
2
3
4
5
6
7
capsule*specimen=create_ptr();
// move from the pointer to the pointer
capsule*rezult=std::move(specimen);
// two equal pointers
assert(specimen==rezult);
// do not erase twice
delete specimen;
Basically, nothing happens. You have two pointers pointing to the same memory address with the single value inside
Two same pointers
std::iter_swap
Let’s now swap two pointers. In C++ lingo pointers are iterators. There is std::iter_swap for swapping two pointers, aka iterators. What do you expect will happen?
1
2
3
4
5
6
7
8
9
capsule*left=create_ptr(false);
capsule*right=create_ptr(true);
// pointer swamping std function
// NOT using std::swap
std::iter_swap(left,right);
delete left;
delete right;
Follow the above through debugger. Surprise? The result is the same as if we have swapped two values not pointers, two instances of capsule. This is not a surprise if you peek into the synopsis of the std::iter_swap :
1
2
3
4
5
6
// synopsis
template<typenameIterator>
voidstd::iter_swap(Iterator p1,Iterator p2)
{
std::swap(*p1,*p2);
}
It simply dereferences the pointers and calls the std::swap on two instances.
The outcome for pointers (aka iterators) of both trivial types and fundamental types is: pointers have not changed, and the values are. It is as simple as that.
But that simplicity yields complexity when dealing with the next type category.