[Lumiera] GUI boost::shared_pointer to std::tr1

Ichthyostega prg at ichthyostega.de
Fri Oct 21 15:32:33 CEST 2011

Am 21.10.2011 14:21, schrieb Michael [Plouj] Ploujnikov:
> Please forgive my ignorance, but I'm just curious, why convert to 
> std::tr1:shared_ptr when std::shared_ptr is already available with even in
> gcc 4.4 (and maybe even earlier)?

yes, indeed, and that's the one we're actually converting to.
We have not yet switched to the new standard, we're rather
just preparing to do so. The final change is then just a
search-and replace "std::tr1" -> to "std::"

But I think not everyone is familiar with the topic,
so let me give some background information....

The old C++ standard included only std::auto_ptr. Good intention,
but the original design seemingly was deterioarted by committee.
They wanted to achieve too much and squeeze all into a single
facility, because (at least that's the impression I got from
reading some publications) they felt that adding several
different smart-ptrs would confuse people. Oh well.

Later in the naughties, a bunch of very capable C++ developers,
several of them also part of the C++ committee, started trying
to do things "the proper way" -- this lead to the "Boost" libraries.

One of these is the boost/memory library. It provides
- boost::shared_ptr : takes ownership, manages lifecycle by ref-counting
- boost::weak_ptr : no ownership, ref-counting, allows to create shared_ptr
- boost::scoped_ptr : takes exclusive ownership, no copying, no ref-count
- boost::intrusive_ptr : like shared_ptr, but manages the ref-count in target
- variants of the above for arrays

The Boost libraries are famous for their compatibility layer. Up to about 2005,
most C++ compilers existing in the wild where a plain joke. They were rather
C compilers on steroids, but often far form even remotely implementing the
fine points of the C++ language. This caused a lot of damage: most people
(including myself) got the impression that C++ itself was a cosmic joke.

Now, the Boost people actually built a compatibility layer out of any
conceivable quirk, allowing to implement real stuff on top, basically
in line with what the standard demands.

Especially boost::shared_ptr became a huge success. Many people felt that
it was what auto_ptr should have been right from start. Thus, a slightly
stripped-down API of shared_ptr was accepted into the "technical report 1",
an appendix of indispensable library extensions expected to become part
of the next standard (which, as we all know, was just accepted some
weeks ago).

Meanwhile, the "G++ guys" had done their homework too. After the not so
successful first redesign attempt (the GCC 3.x series), the GCC 4.x line
basically got the internals right, and since about G++ 4.2, you can use
this beast as a real C++ compiler without running in any serious problems.
Form that point on, the greatest problem was un-learning the quirks.

Obviously any compiler needs a tailored runtime library. For G++, this is
the libstdc++. The folks involved into that effort were ambitious to provide
the contents of the TR1 report. They started out with the respective
implementations from the Boost libraries. The Boost people supported that
by donating their implementation (read: they re-licensed those parts under
the LGPL).

For the shard_ptr, this libstdc++ version, while based on boost::shared_ptr,
is really a different implementation: It doesn't need the compatibility layer,
because it can target a single well known compiler. Even more, it can use
special support hooks provided by the compiler, as the compiler writers
and the library writers are "basically the same people".

Let me finish that little historical excursion :-D
with a more technical side note.

The purpose of shard_ptr is to take ownership of an heap allocated object.
That's a kind of collaborative ownership: all shared_ptr instances involved
collaborate, and when the last one goes out of scope, the destructor function
is invoked. Now this creates a twist: all these shared_ptr instances need to
communicate "behind the scenes", while we can't assume anything about thread
safety. The obvious solution would be to use a shared mutex, but that would
kill the performance (actually, create lock contention). Thus, both
boost::shared_ptr and the shared_ptr of the libstdc++ use a so called
"lock free implementation": This uses some clever trickery to avoid a
race when updating the shared usage count.

But all the trickery can't overcome the necessity of a "memory barrier".
Even if we manage to make the update in one shot, we need a means to
"publish" the changed value of the shared usage count to all the other
Cores in a multicore system. Because some other core could right at that
moment execute other code in another thread, which involves another instance
of our shared_ptr gang. And while the boost implementation relies here on
special nonportable quirks compiled in for each of the possible compilers,
the libstdc++ version can call a special GNU extension hook provided by
GCC; the compiler will then care to generate the proper assembly to
ensure the necessary cache flush to publish the changed values.

Bottom line: we should care to use one of these two implementations,
and obviously, the libstc++ implementation is preferable.

We could consider toggling to the new C++11 standard eventually, but
my gut feeling tells me that we should better wait maybe a year and
let other people be the early adopters. We could indeed benefit from
three features of the new standard right now, but we managed to have
viable workarounds (based on boost), and we can well continue to do
so for yet some time to come.


More information about the Lumiera mailing list