On 29/11/2007, Warren Young <mysqlpp@stripped> wrote:
> Jonathan Wakely wrote:
>
> > ...safe against self-assignment...
>
> I don't see any checks for self-assignment in your code. It sort of
> happens implicitly in assign(const ThisType&) because the refcount just
> goes up and then comes right back down, but this is wasteful. And in
No! :)
Yes it happens implicitly, that's precisely the point. How many times
does self-assignment happen? Seriously. It is almost always the
result of a programming error, or maybe occasionally setting a
collection of objects to a single value which happens to be in the
collection _occasionally_ - let's generously assume it's 0.1% of all
assignments.
If it does happen, and your class isn't safe for self-assignment, very
bad things happen. Nasal demons and all sorts. So we've all learnt to
prevent that. But checking if (this ==&rhs) on *every* assignment is
what's really wasteful. In 99.9% of assignments the rhs.use_count()
goes up, and this->use_count() goes down. It's only wasteful in the
0.1% of cases where this == &rhs and the same refcount goes up and
down.
So by putting the explicit check back you've helped that tiny fraction
of cases, at the expense of the common case. Providing an O(1)
nothrow swap, and implementing the assignment operator in terms of
copy and swap is the canonical assignment operator. And in The Future
(cue sci-fi music) will be even more efficient thanks to
rvalue-references and move-semantics.
> the assign(T*) case, I'm pretty sure assigning the same pointer will
> result in a double-delete. I've added explicit checks to both assign()
> overloads.
Pleeeeeease remove it :)
Jon