For a long time time I though that the correct way to implement a copy assignment (for a non trivial class) was to use the copy-swap idiom.
struct A{
... pointer to data
A(A const& other){
... complicated stuff, allocation, loops, etc
}
void swap(A& other){... cheap stuff ...}
A& operator=(A const& other){
A tmp{other};
swap(other);
return *this;
}
};
But then I heard this talk https://www.youtube.com/watch?v=vLinb2fgkHk by Howard Hinnant where he says that the copy-swap idiom is good to fulfill the strong-exception guarrantee but it is an overkill in general.
He mentions that here: https://youtu.be/vLinb2fgkHk?t=2616
So he suggests implement the copy assignment explicitly and have a separate function strong_assing(A& target, A const& source)
containing the copy-swap.
What I don't understand is how A& operator=(A const& other)
should be implemented then?
Does he suggest to have something like this?
A& operator=(A const& other){
... don't allocate if not necessary
... loop element by element
... clean the bare minimum if there is a throw
}
Is this what std::vector
implementations do then?
That is, they do not use the copy-swap idiom at the end?
Doesn't the standard vector requires the strong-exception guarantee?
std::vector
can copy a buffer internally, then swap it. So it does not need copy and swap at the level of the assignment operator parameter. – RaiA::operator=(const A& __x){if (this != &__x){...} ...};
(used in your linked code) but apparently it is still the correct way to start when only the basic-exception guarantee is necessary. no? – Byssusoperator=
start (and end) with= default
. It is difficult for me to give a general recipe for this function. It should give the lhs the state of the rhs, keep the rhs state unchanged, usually create two distinct (unlinked) values, not leak any memory, have at least basic exception safety, and be as high performance as possible. A decent first cut at estimating performance is to count the number of allocations and deallocations. – Logisticstd::vector
doesn't have the strong exception guarantee. And that is not bad thing since the strong exception guarantee is not required. I think I also understand that copy-swap (for a vector-like) will always call allocate for the third object, while obviously there are (runtime) cases in which allocations would not be necessary to copy a container. – Byssusvector::push_back
. The design philosophy that the committee used for deciding when to provide the strong guarantee was "when it does not add a performance penalty to do so." – Logistic