Boost logo

Boost :

From: Beman Dawes (bdawes_at_[hidden])
Date: 2001-03-18 17:27:09

At 10:46 AM 3/18/2001, alexoss_at_[hidden] wrote:

>I created my own reference-counted smart pointer class a long time
>ago and have used it quite successfully. However, it suffered from
>what kept on turning out to be a serious drawback: it could not be
>used for static variables, because it relied on a global structure to
>keep track of the allocations it was tracking.
>The boost::shared_ptr class is a godsend: it makes very clever use of
>new language features like the "explicit" keyword, and templatized
>member functions.

Glad you are getting good mileage out of it. We really should use a memory
pool for the counts, deal with some base and derived conversion issues,
etc..., but what is there seems to serve a lot of people's needs.

> I have taken the shared_ptr code and modified it
>for my purposes, replacing my venerable but limited class. While
>test compiling, I have come up with a few questions...
>1. In share(), shouldn't the code "if (pn != rpn)" be "if (px !=

They are equivalent. Something is disastrously wrong if (pn != rpn) == (px
!= rpx). Think about it. If the two object pointers point to the same
object, the two count pointer had better point to the same count. I'll add
a comment to the code mentioning that. Similar in shared_array. I guess
we could assert ((pn==rpn) == (px==rpx)), but it doesn't seem worth it to
me. Greg?

>2. Why does reset(T *) have different code than operator=
>(auto_ptr)? They seem to perform exactly the same operation
>(replacing the member values with those passed in as a parameter),
>but reset() seems to have a more complicated structure, which is
>unnecessary in operator =(). Wouldn't reset() work just as well like:
> void reset(T *p = 0)
> {
> if (px == p) return;
> if (*pn == 1) { delete px; }
> else
> {
> long *tmp = new long(1);
> --*pn;
> pn = tmp;
> }
> px = p;
> }

If the new throws bad_alloc, p will not be deleted with your code,
resulting in a memory leak.

>3. I used the same code in the reset() above to create an operator =
>(T *). Is there any harm to providing such an assignment operator,
>especially given the existence of a constructor with a pointer
>parameter, as well as reset() itself?

IIRC, the auto_ptr practice was followed, and it supplies reset() rather
than an assignment operator as less error prone. The thought was that the
reset() name would make the user think twice, and only use it if actually
intended. Greg may want to correct my memory.

>4. Why is "long" the type of the reference count variable? Why
>isn't it "unsigned long"? The number of referencing pointers cannot
>be negative.

I don't know. Some highly experienced programmers prefer signed to
unsigned if both are large enough for the usage, because if a bug drives
the value negative, this creates an easier to detect and debug situation
that what happens with an unsigned.

>5. Is the presence of "typedef T element_type;" a means by which
>greater compatibility between shared_ptr and the standard library can
>be established?

Yes. It may help when the shared_ptr is used in a generic programming

>6. Although I see that it "works" (that is, without it, I get
>compilation errors in BCB 5), I cannot fully understand:
>template<typename Y> friend class shared_ptr;
>What does this code do, exactly?

Allows access to private members by related classes used in member
templates like template<typename Y>
       shared_ptr& operator=(const shared_ptr<Y>& r)

>7. Are there situations in which use_count() and unique() are
>helpful to have? I've never needed to know this information about my
>old reference-counted pointer class.

For sure, unique() is. use_count() is more controversial. Greg argued
against it, IIRC. I'm not sure either of us had a specific use in mind.

>Thanks so much for your help, and of course for "pointing" me in the
>right direction!

Thanks for your interest. It's a strong motivation to hear people actually
use the Boost libraries.


Boost list run by bdawes at, gregod at, cpdaniel at, john at