Making swap faster, easier to use and exception-safe - c++

I could not sleep last night and started thinking about std::swap. Here is the familiar C++98 version:
template <typename T>
void swap(T& a, T& b)
{
T c(a);
a = b;
b = c;
}
If a user-defined class Foo uses external ressources, this is inefficient. The common idiom is to provide a method void Foo::swap(Foo& other) and a specialization of std::swap<Foo>. Note that this does not work with class templates since you cannot partially specialize a function template, and overloading names in the std namespace is illegal. The solution is to write a template function in one's own namespace and rely on argument dependent lookup to find it. This depends critically on the client to follow the "using std::swap idiom" instead of calling std::swap directly. Very brittle.
In C++0x, if Foo has a user-defined move constructor and a move assignment operator, providing a custom swap method and a std::swap<Foo> specialization has little to no performance benefit, because the C++0x version of std::swap uses efficient moves instead of copies:
#include <utility>
template <typename T>
void swap(T& a, T& b)
{
T c(std::move(a));
a = std::move(b);
b = std::move(c);
}
Not having to fiddle with swap anymore already takes a lot of burden away from the programmer.
Current compilers do not generate move constructors and move assignment operators automatically yet, but as far as I know, this will change. The only problem left then is exception-safety, because in general, move operations are allowed to throw, and this opens up a whole can of worms. The question "What exactly is the state of a moved-from object?" complicates things further.
Then I was thinking, what exactly are the semantics of std::swap in C++0x if everything goes fine? What is the state of the objects before and after the swap? Typically, swapping via move operations does not touch external resources, only the "flat" object representations themselves.
So why not simply write a swap template that does exactly that: swap the object representations?
#include <cstring>
template <typename T>
void swap(T& a, T& b)
{
unsigned char c[sizeof(T)];
memcpy( c, &a, sizeof(T));
memcpy(&a, &b, sizeof(T));
memcpy(&b, c, sizeof(T));
}
This is as efficient as it gets: it simply blasts through raw memory. It does not require any intervention from the user: no special swap methods or move operations have to be defined. This means that it even works in C++98 (which does not have rvalue references, mind you). But even more importantly, we can now forget about the exception-safety issues, because memcpy never throws.
I can see two potential problems with this approach:
First, not all objects are meant to be swapped. If a class designer hides the copy constructor or the copy assignment operator, trying to swap objects of the class should fail at compile-time. We can simply introduce some dead code that checks whether copying and assignment are legal on the type:
template <typename T>
void swap(T& a, T& b)
{
if (false) // dead code, never executed
{
T c(a); // copy-constructible?
a = b; // assignable?
}
unsigned char c[sizeof(T)];
std::memcpy( c, &a, sizeof(T));
std::memcpy(&a, &b, sizeof(T));
std::memcpy(&b, c, sizeof(T));
}
Any decent compiler can trivially get rid of the dead code. (There are probably better ways to check the "swap conformance", but that is not the point. What matters is that it's possible).
Second, some types might perform "unusual" actions in the copy constructor and copy assignment operator. For example, they might notify observers of their change. I deem this a minor issue, because such kinds of objects probably should not have provided copy operations in the first place.
Please let me know what you think of this approach to swapping. Would it work in practice? Would you use it? Can you identify library types where this would break? Do you see additional problems? Discuss!

So why not simply write a swap template that does exactly that: swap the object representations*?
There's many ways in which an object, once being constructed, can break when you copy the bytes it resides in. In fact, one could come up with a seemingly endless number of cases where this would not do the right thing - even though in practice it might work in 98% of all cases.
That's because the underlying problem to all this is that, other than in C, in C++ we must not treat objects as if they are mere raw bytes. That's why we have construction and destruction, after all: to turn raw storage into objects and objects back into raw storage. Once a constructor has run, the memory where the object resides is more than only raw storage. If you treat it as if it weren't, you will break some types.
However, essentially, moving objects shouldn't perform that much worse than your idea, because, once you start to recursively inline the calls to std::move(), you usually ultimately arrive at where built-ins are moved. (And if there's more to moving for some types, you'd better not fiddle with the memory of those yourself!) Granted, moving memory en bloc is usually faster than single moves (and it's unlikely that a compiler might find out that it could optimize the individual moves to one all-encompassing std::memcpy()), but that's the price we pay for the abstraction opaque objects offer us. And it's quite small, especially when you compare it to the copying we used to do.
You could, however, have an optimized swap() using std::memcpy() for aggregate types.

This will break class instances that have pointers to their own members. For example:
class SomeClassWithBuffer {
private:
enum {
BUFSIZE = 4096,
};
char buffer[BUFSIZE];
char *currentPos; // meant to point to the current position in the buffer
public:
SomeClassWithBuffer();
SomeClassWithBuffer(const SomeClassWithBuffer &that);
};
SomeClassWithBuffer::SomeClassWithBuffer():
currentPos(buffer)
{
}
SomeClassWithBuffer::SomeClassWithBuffer(const SomeClassWithBuffer &that)
{
memcpy(buffer, that.buffer, BUFSIZE);
currentPos = buffer + (that.currentPos - that.buffer);
}
Now, if you just do memcpy(), where would currentPos point? To the old location, obviously. This will lead to very funny bugs where each instance actually uses another's buffer.

Some types can be swapped but cannot be copied. Unique smart pointers are probably the best example. Checking for copyability and assignability is wrong.
If T isn't a POD type, using memcpy to copy/move is undefined behavior.
The common idiom is to provide a method void Foo::swap(Foo& other) and a specialization of std::swap<Foo>. Note that this does not work with class templates, …
A better idiom is a non-member swap and requiring users to call swap unqualified, so ADL applies. This also works with templates:
struct NonTemplate {};
void swap(NonTemplate&, NonTemplate&);
template<class T>
struct Template {
friend void swap(Template &a, Template &b) {
using std::swap;
#define S(N) swap(a.N, b.N);
S(each)
S(data)
S(member)
#undef S
}
};
The key is the using declaration for std::swap as a fallback. The friendship for Template's swap is nice for simplifying the definition; the swap for NonTemplate might also be a friend, but that's an implementation detail.

I deem this a minor issue, because
such kinds of objects probably should
not have provided copy operations in
the first place.
That is, quite simply, a load of wrong. Classes that notify observers and classes that shouldn't be copied are completely unrelated. How about shared_ptr? It obviously should be copyable, but it also obviously notifies an observer- the reference count. Now it's true that in this case, the reference count is the same after the swap, but that's definitely not true for all types and it's especially not true if multi-threading is involved, it's not true in the case of a regular copy instead of a swap, etc. This is especially wrong for classes that can be moved or swapped but not copied.
because in general, move operations
are allowed to throw
They are most assuredly not. It is virtually impossible to guarantee strong exception safety in pretty much any circumstance involving moves when the move might throw. The C++0x definition of the Standard library, from memory, explicitly states any type usable in any Standard container must not throw when moving.
This is as efficient as it gets
That is also wrong. You're assuming that the move of any object is purely it's member variables- but it might not be all of them. I might have an implementation-based cache and I might decide that within my class, I should not move this cache. As an implementation detail it is entirely within my rights not to move any member variables that I deem are not necessary to be moved. You, however, want to move all of them.
Now, it's true that your sample code should be valid for a lot of classes. However, it's extremely very definitely not valid for many classes that are completely and totally legitimate, and more importantly, it's going to compile down to that operation anyway if the operation can be reduced to that. This is breaking perfectly good classes for absolutely no benefit.

your swap version will cause havoc if someone uses it with polymorphic types.
consider:
Base *b_ptr = new Base(); // Base and Derived contain definitions
Base *d_ptr = new Derived(); // of a virtual function called vfunc()
yourmemcpyswap( *b_ptr, *d_ptr );
b_ptr->vfunc(); //now calls Derived::vfunc, while it should call Base::vfunc
d_ptr->vfunc(); //now calls Base::vfunc while it should call Derived::vfunc
//...
this is wrong, because now b contains the vtable of the Derived type, so Derived::vfunc is invoked on a object which isnt of type Derived.
The normal std::swap only swaps the data members of Base, so this is OK with std::swap

Related

c++ type trait to say "trivially movable" - examples of

I would define "trivially movable" by
Calling the move constructor (or the move assignment operator) is
equivalent to memcpy the bytes to the new destination and not calling
the destructor on the moved-from object.
For instance, if you know that this property holds, you can use realloc to resize a std::vector or a memory pool.
Types failing this would typically have pointers to their contents that needs to be updated by the move constructor/assignment operator.
There is no such type traits in the standard that I can find.
I am wondering whether this already has a (better) name, whether it's been discussed and whether there are some libraries making use of such a trait.
Edit 1:
From the first few comments, std::is_trivially_move_constructible and std::is_trivially_move_assignable are not equivalent to what I am looking for.
I believe they would give true for types containing pointers to themselves, since reading your own member seems to fall under "trivial" operation.
Edit 2:
When properly implemented, types which point to themselves won't be trivially_move_constructible or move_assignable because the move ctor / move assignment operator are not trivial anymore.
Though, we ought to be able to say that unique_ptr can be safely copied to a new location provided we don't call its destructor.
I think what you need is std::is_trivially_relocatable from proposal P1144. Unfortunately the proposal didn't make it into C++20, so we shouldn't expect it before 2023. Which is sad, because this type trait would enable great optimizations for std::vector and similar types.
Well, this got me thinking... It is very important to overload type traits of structs that hold a pointer to themselves.
The following code demonstrates how fast a bug can creep in code, when type_traits are not defined properly.
#include <memory>
#include <type_traits>
struct A
{
int a;
int b;
int* p{&a};
};
int main()
{
auto p = std::make_unique<A>();
A a = std::move(*p.get()); // gets moved here, a.p is dangling.
return std::is_move_assignable<A>::value; // <-- yet, this returns true.
}

Why are there so many specializations of std::swap?

While looking at the documentation for std::swap, I see a lot of specializations.
It looks like every STL container, as well as many other std facilities have a specialized swap.
I thought with the aid of templates, we wouldn't need all of these specializations?
For example,
If I write my own pair it works correctly with the templated version:
template<class T1,class T2>
struct my_pair{
T1 t1;
T2 t2;
};
int main() {
my_pair<int,char> x{1,'a'};
my_pair<int,char> y{2,'b'};
std::swap(x,y);
}
So what it is gained from specializing std::pair?
template< class T1, class T2 >
void swap( pair<T1,T2>& lhs, pair<T1,T2>& rhs );
I'm also left wondering if I should be writing my own specializations for custom classes,
or simply relying on the template version.
So what it is gained from specializing std::pair?
Performance. The generic swap is usually good enough (since C++11), but rarely optimal (for std::pair, and for most other data structures).
I'm also left wondering if I should be writing my own specializations for custom classes, or simply relying on the template version.
I suggest relying on the template by default, but if profiling shows it to be a bottleneck, know that there is probably room for improvement. Premature optimization and all that...
std::swap is implemented along the lines of the code below:
template<typename T> void swap(T& t1, T& t2) {
T temp = std::move(t1);
t1 = std::move(t2);
t2 = std::move(temp);
}
(See "How does the standard library implement std::swap?" for more information.)
So what it is gained from specializing std::pair?
std::swap can be specialized in the following way (simplified from libc++):
void swap(pair& p) noexcept(is_nothrow_swappable<first_type>{} &&
is_nothrow_swappable<second_type>{})
{
using std::swap;
swap(first, p.first);
swap(second, p.second);
}
As you can see, swap is directly invoked on the elements of the pair using ADL: this allows customized and potentially faster implementations of swap to be used on first and second (those implementations can exploit the knowledge of the internal structure of the elements for more performance).
(See "How does using std::swap enable ADL?" for more information.)
Presumably this is for performance reasons in the case that the pair's contained types are cheap to swap but expensive to copy, like vector. Since it can call swap on first and second instead of doing a copy with temporary objects it may provide a significant improvement to program performance.
The reason is performance, especially pre c++11.
Consider something like a "Vector" type. The Vector has three fields: size, capacity and a pointer to the actual data. It's copy constructor and copy assignment copy the actual data. The C++11 version also has a move constructor and move assignment that steal the pointer, setting the pointer in the source object to null.
A dedicated Vector swap implementation can simply swap the fields.
A generic swap implementation based on the copy constructor, copy assignment and destructor will result in data copying and dynamic memory allocation/deallocation.
A generic swap implementation based on the move constructor, move assignment and destructor will avoid any data copying or memory allocation but it will leave some redundant nulling and null-checks which the optimiser may or may not be able to optimise away.
So why have a specialised swap implementation for "Pair"? For a pair of int and char there is no need. They are plain old data types so a generic swap is just fine.
But what if I have a pair of say Vector and String ? I want to use the specialist swap operations for those types and so I need a swap operation on the pair type that handles it by swapping it's component elements.
The most efficient way to swap two pairs is not the same as the most efficient way to swap two vectors. The two types have a different implementation, different member variables and different member functions.
There is no just generic way to "swap" two objects in this manner.
I mean, sure, for a copyable type you could do this:
T tmp = a;
a = b;
b = tmp;
But that's horrendous.
For a moveable type you can add some std::move and prevent copies, but then you still need "swap" semantics at the next layer down in order to actually have useful move semantics. At some point, you need to specialise.
There is a rule (I think it comes from either Herb Sutter's Exceptional C++ or Scott Meyer's Effective C++ series) that if your type can provide a swap implementation that does not throw, or is faster than the generic std::swap function, it should do so as member function void swap(T &other).
Theoretically, the generic std::swap() function could use template magic to detect the presence of a member-swap and call that instead of doing
T tmp = std::move(lhs);
lhs = std::move(rhs);
rhs = std::move(tmp);
but no-one seems to have thought about that one, yet, so people tend to add overloads of free swap in order to call the (potentially faster) member-swap.

why should we use std::move semantic with unique pointers?

Conceptual Question
Say we have simple example like this:
void foo(std::unique_ptr<int> ptr)
{
std::cout << *ptr.get() << std::endl;
}
int main()
{
std::unique_ptr<int> uobj = std::make_unique<int>(4);
foo(uobj ); // line-(1) Problem ,but Alternative -> foo(std::move(uobj ))
std::unique_ptr<int> uobjAlt = uobj; // line-(2) Problem ,but Alternative -> std::unique_ptr<int> uobjAlt = std::move(uobj);
return EXIT_SUCCESS;
}
We know simply std::unique_ptr bound with concept of resource owning by single owner with moving resource among multiple owners while shared_ptr has opposite aspect.
As example shown above, when you look at line-(1) & line-(2) you notice that some standard rules are being violated because std::unique_ptr has(deleted) no both copy constructors and copy assignable operators defined, but In order to avoid compilation errors we have to use std::move function instead.
Problem
Why modern C++ compiler cannot automatically generate instructions to move the resource among unique pointers in line-(1) and line-(2)? because we know unique pointer intentionally design for that. Why should we use std::move explicitly to instruct the machine to move ownership of the resource?
std::unique_ptr nothing but class template.we know that, But situations addressed in line-1 and line -2 having issues while compiler complain about copying unique_pointers not allowed(deleted functions).why we having these kind of errors why c++ standard and compiler vendors cannot override this concept?
Unique Pointer intentionally designed for the purpose of moving resource while passing its ownership, when we pass it as function/constructor argument or assign to another unique pointer, it conceptually should move resource with ownership nothing else, but why we should use std::move to convey compiler to actual move, why don't we have a freedom to call line-(1) and line-(2) as it is? (while intelligent compiler generate automatic move operation among unique pointers for us, unless there is const or non-const reference passing).
(Sorry for long description and broken English) Thank you.
unique_ptr is useful to free memory for you automatically when uobj goes out of scope. That's its job. So, since it has 1 pointer it has to free, it has to be unique, and hence its name: unique_ptr!
When you do something like this:
std::unique_ptr<int> uobjAlt = uobj;
You're issuing a copy operation, but, you're not supposed to copy the pointer, because copying means that both objects uobjAlt and uobj must both be freed, which will directly lead to a segmentation fault and a crash. So, by using std::move, you're moving ownership from one object to another.
If you want to have multiple pointers to a single object, you should consider using std::shared_ptr.
This has nothing to do with whether the compiler can do this. It certainly could work that way, and in fact, it did work that way prior to C++11 with std::auto_ptr<>. It was horrible.
std::auto_ptr<int> x = std::auto_ptr<int>(new int(5));
std::auto_ptr<int> y = x;
// Now, x is NULL
The problem here is that the = sign usually means "copy from x to y", but in this case what is happening is "move from x to y, invalidating x in the process". Yes, if you are a savvy programmer you would understand what is going on here and it wouldn't surprise you, at least not all of the time. However, in more common situations it would be horribly surprising:
Here's MyClass.h:
class MyClass {
private:
std::auto_ptr<Type> my_field;
...
};
Here's MyClass.cpp:
void MyClass::Method() {
SomeFunction(my_field);
OtherFunction(my_field);
}
Here's Functions.h:
// Which overload, hmm?
void SomeFunction(Type &x);
void SomeFunction(std::auto_ptr<Type> x);
void OtherFunction(const std::auto_ptr<Type> &x);
Now you have to look at three different files before you can figure out that my_field is set to NULL. With std::unique_ptr you only have to look at one:
void MyClass::Method() {
SomeFunction(std::move(my_field));
OtherFunction(my_field);
}
Just looking at this one function I know that it's wrong, I don't have to figure out which overload is being used for SomeFunction, and I don't have to know what the type of my_field is. There's definitely a balance that we need to have between making things explicit and implicit. In this case, the fact that you couldn't explicitly tell the difference between moving and copying a value in C++ was such a problem that rvalue references, std::move, std::unique_ptr, etc. were added to C++ to clear things up, and they're pretty amazing.
The other reason why auto_ptr was so bad is because it interacted poorly with containers.
// This was a recipe for disaster
std::vector<std::auto_ptr<Type> > my_vector;
In general, many templates worked poorly with auto_ptr, not just containers.
If the compiler were allowed to auto-infer move semantics for types such as std::unique_ptr, code like this would break:
template<typename T> void simple_swap(T& a, T& b) {
T tmp = a;
a = b;
b = tmp;
}
The above counts on tmp being a copy of a (because it continues to use a as the left-hand side of as assignment operator). There is code in the standard algorithms which actually requires temporary copies of container values. Inferring moves would break them, causing crashes at run-time. This is why std::auto_ptr was warned against ever being used in STL containers.

Exception Safety: Benefits of a nothrow swap

If a type has a swap function which cannot fail, this can make it easier for other functions to provide the strong exception safety guarantee. This is because we can first do all of the function's work which may fail "off to the side", and then commit the work using non-throwing swaps.
However, are there any other benefits of guaranteeing that swap will never fail?
For example, is there a situation in which the presence of a no-fail swap makes it easier for another function to provide the basic guarantee?
Let's say I do this:
class C {
T a, b; // invariant: a > b
void swap(C& other);
};
It seems that there's no way to implement C::swap() with basic guarantee if T::swap(T&) might throw. I'd have to add a level of indirection and store T* instead of T.

Benefits of a swap function?

Browsing through some C++ questions I have often seen comments that a STL-friendly class should implement a swap function (usually as a friend.) Can someone explain what benefits this brings, how the STL fits into this and why this function should be implemented as a friend?
For most classes, the default swap is fine, however, the default swap is not optimal in all cases. The most common example of this would be a class using the Pointer to Implementation idiom. Where as with the default swap a large amount of memory would get copied, is you specialized swap, you could speed it up significantly by only swapping the pointers.
If possible, it shouldn't be a friend of the class, however it may need to access private data (for example, the raw pointers) which you class probably doesn't want to expose in the class API.
The standard version of std::swap() will work for most types that are assignable.
void std::swap(T& lhs,T& rhs)
{
T tmp(lhs);
lhs = rhs;
rhs = tmp;
}
But it is not an optimal implementation as it makes a call to the copy constructor followed by two calls to the assignment operator.
By adding your own version of std::swap() for your class you can implement an optimized version of swap().
For example std::vector. The default implementation as defined above would be very expensive as you would need to make copy of the whole data area. Potentially release old data areas or re-allocate the data area as well as invoke the copy constructor for the contained type on each item copied. A specialized version has a very simple easy way to do std::swap()
// NOTE this is not real code.
// It is just an example to show how much more effecient swaping a vector could
// be. And how using a temporary for the vector object is not required.
std::swap(std::vector<T>& lhs,std::vector<T>& rhs)
{
std::swap(lhs.data,rhs.data); // swap a pointer to the data area
std::swap(lhs.size,rhs.size); // swap a couple of integers with size info.
std::swap(lhs.resv,rhs.resv);
}
As a result if your class can optimize the swap() operation then you should probably do so. Otherwise the default version will be used.
Personally I like to implement swap() as a non throwing member method. Then provide a specialized version of std::swap():
class X
{
public:
// As a side Note:
// This is also useful for any non trivial class
// Allows the implementation of the assignment operator
// using the copy swap idiom.
void swap(X& rhs) throw (); // No throw exception guarantee
};
// Should be in the same namespace as X.
// This will allows ADL to find the correct swap when used by objects/functions in
// other namespaces.
void swap(X& lhs,X& rhs)
{
lhs.swap(rhs);
}
If you want to swap (for example) two vectors without knowing anything about their implementation, you basically have to do something like this:
typedef std::vector<int> vec;
void myswap(vec &a, vec &b) {
vec tmp = a;
a = b;
b = tmp;
}
This is not efficient if a and b contain many elements since all those elements are copied between a, b and tmp.
But if the swap function would know about and have access to the internals of the vector, there might be a more efficient implementation possible:
void std::swap(vec &a, vec &b) {
// assuming the elements of the vector are actually stored in some memory area
// pointed to by vec::data
void *tmp = a.data;
a.data = b.data;
b.data = tmp;
// ...
}
In this implementation just a few pointers need to be copied, not all the elements like in the first version. And since this implementation needs access to the internals of the vector it has to be a friend function.
I interpreted your question as basically three different (related) questions.
Why does STL need swap?
Why should a specialized swap be implemented (i.s.o. relying on the default swap)?
Why should it be implemented as a friend?
Why does STL need swap?
The reason an STL friendly class needs swap is that swap is used as a primitive operation in many STL algorithms. (e.g. reverse, sort, partition etc. are typically implemented using swap)
Why should a specialized swap be implemented (i.s.o. relying on the default swap)?
There are many (good) answers to this part of your question already. Basically, knowing the internals of a class frequently allows you to write a much more optimized swap function.
Why should it be implemented as a friend?
The STL algorithms will always call swap as a free function. So it needs to be available as a non member function to be useful. And, since it's only beneficial to write a customized swap when you can use knowledge of internal structures to write a much more efficient swap, this means your free function will need access to the internals of your class, hence a friend.
Basically, it doesn't have to be a friend, but if it doesn't need to be a friend, there's usually no reason to implement a custom swap either.
Note that you should make sure the free function is inside the same namespace as your class, so that the STL algorithms can find your free function via Koening lookup.
One other use of the swap function is to aid exception-safe code: http://www.gotw.ca/gotw/059.htm
Efficiency:
If you've got a class that holds (smart) pointers to data then it's likely to be faster to swap the pointers than to swap the actual data - 3 pointer copies vs. 3 deep copies.
If you use a 'using std::swap' + an unqualified call to swap (or just a qualified call to boost::swap), then ADL will pick up the custom swap function, allowing efficient template code to be written.
Safety:
Pointer swaps (raw pointers, std::auto_ptr and std::tr1::shared_ptr) do not throw, so can be used to implement a non-throwing swap. A non-throwing swap makes it easier to write code that provides the strong exception guarantee (transactional code).
The general pattern is:
class MyClass
{
//other members etc...
void method()
{
MyClass finalState(*this);//copy the current class
finalState.f1();//a series of funcion calls that can modify the internal
finalState.f2();//state of finalState and/or throw.
finalState.f3();
//this only gets call if no exception is thrown - so either the entire function
//completes, or no change is made to the object's state at all.
swap(*this,finalState);
}
};
As for whether it should be implemented as friend; swapping usually requires knowledge of implementation details. It's a matter of taste whether to use a non-friend that calls a member function or to use a friend.
Problems:
A custom swap is often faster than a single assignment - but a single assignment is always faster than the default three assignment swap. If you want to move an object, it's impossible to know in a generic way whether a swap or assignment would be best - a problem which C++0x solves with move constructors.
To implement assignment operators:
class C
{
C(C const&);
void swap(C&) throw();
C& operator=(C x) { this->swap(x); return *this; }
};
This is exception safe, the copy is done via the copy constructor when you pass by value, and the copy can be optimized out by the compiler when you pass a temporary (via copy elision).