Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2002-05-08 05:21:19


From: "Gennadiy Rozental" <rogeeff_at_[hidden]>
> I think that shared_ptr named shared not because you "can use different
> deallocators" with the same type (though in some cases it is very
> convenient), but because it model some "Idea" of sharing. The way this
> sharing is achieved is not important - it still should be shared_ptr.
While
> the way how pointer/resource is destroyed is secondary in this sense. Why
> don't you name you semantic: ptr_with_custom_deleter?

Do you argue that you have the right to use the name "shared_ptr" in a way
that is incompatible with the current specification, and that the current
implementation should be renamed to better reflect your ideas of sharing?
That would be great.

> In some cases when we want to emphasize type of sharing in use we may name
> smart pointer as intrusive_ptr or ref_linked_ptr. But what in a name? The
> real issue for me is to understand: do we need "unified" smart_ptr, why,
and
> how it should like.

What does "unified" mean?

shared_ptr's current semantics are carefully crafted to model some of the
raw pointer strengths (the same features can be weaknesses in other
situations, and shared_ptr wouldn't be appropriate here, but I digress.)

In particular:

* shared_ptr works with incomplete classes.

* shared_ptr<T> is a pointer to T and has the same ("unified") interface,
regardless of how T has been allocated (or whether it uses intrusive
counting.)

* shared_ptr supports the usual pointer conversions.

This allows shared_ptr to be used for implementation hiding in situations
where other smart pointers aren't applcable, but raw pointers fare well:

[1]

class file;

shared_ptr<file> fopen(char const * name);
size_t fread(shared_ptr<file> f, void * buffer, size_t n);

[2]

class file
{
    struct impl;
    shared_ptr<impl> pi_;

public:

    explicit file(char const * name);
    size_t read(void * buffer, size_t n);
};

[3]

struct interface
{
    virtual void method() = 0;
};

shared_ptr<interface> createInstance();

Note that the implementor of createInstance() can change the counting type
or the allocation mechanism without breaking any client code; if
createInstance() is in a shared library, the client doesn't even have to
relink. (This applies to the other examples as well.)

In short, one of the uses of shared_ptr is for implementation hiding; it
insulates the client from the particulars of the implementation. It can be
used with COM-allocated objects in situations where the client does not care
where the object returned is COM.

In contrast, in situations where the client does care about the COM-ness of
the object, one should use a genuine COM smart pointer (which has a
different, non-"unified", interface, understands QueryInterface etc.) There
is no interoperability problem between different COM smart pointers (or
intrusive pointers in general) since you can construct an intrusive pointer
from a raw pointer.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk