Boost logo

Boost :

From: scleary_at_[hidden]
Date: 2000-10-19 15:19:43


> I don't follow your explanation for the last line:
>
> > static void test2()
> > {
> > std::vector<BaseNodePtr> v0;
> > std::vector<DerivedNodePtr> v1;
> >
> > v1.push_back(DerivedNodePtr(new DerivedNode));
> > v0.push_back(v1[0]);
> > }
> >
> > The last line of code there constructs a new BaseNodePtr from a
> > DerivedNodePtr, which compiles because there's an implicit pointer
> > conversion from DerviedNode to BaseNode.
>
> v1[0] is a DerivedNodePtr, not a DerivedNode, so the implicit pointer
> conversion from DerivedNode to BaseNode isn't applicable.

Forget BOOST_SMART_PTR_CONVERSION -- it doesn't have anything to do with
this. What I said above was assuming that member templates are enabled.
With that assumption, let's look at "v0.push_back(v1[0])":

v1[0] is a DerivedNodePtr. That is correct. However, the compiler will try
to construct a BaseNodePtr to put into v0 when we call push_back. Now, (if
member templates are available), the compiler will find the template copy
constructor, which is:
   template<typename Y>
      shared_ptr(const shared_ptr<Y>& r) : px(r.px) { // never throws
         ++*(pn = r.pn);
      }

The "px" is the pointer to the object that is reference counted. The "pn"
is the pointer to the reference count, which will also be destroyed when it
reaches 0. So the templated copy constructor 1) copies the pointer, and 2)
shares the same reference count and increments it.

It is in step (1), above, that the implicit pointer conversion from
DerivedNode* to BaseNode* takes place. If you tried to copy-construct a
DerivedNodePtr from a BaseNodePtr, it wouldn't compile because it would try
to do the implicit pointer conversion the other way, from BaseNode* to
DerivedNode*.

> The one-level-of-implicit-conversion rule
> doesn't prevent this sequence, but I don't understand what enables it.

To really understand proper design of smart pointers (including the cute
side-stepping of that one-user-defined-conversion rule), you need to fully
understand std::auto_ptr. References at end of e-mail.

> Wouldn't this work instead?
>
> v0.push_back(v1[0].get());

AAA!!! Don't do that! Sorry -- I just had a minor heart attack :). Yes,
this will compile. No, this won't work :). Remember, you're dealing with
smart pointers -- they delete their objects, like auto_ptr. What happens if
you say:
  std::auto_ptr<DerivedNode> a(new DerivedNode());
  std::auto_ptr<BaseNode> b(a.get());
Not good, right? (You end up with *two* smart pointers thinking they own
the same object). You'll get the same result with boost's smart pointers.

"get()" on auto_ptr (or other smart pointers) is kind of like "c_str()" on
string -- they're a visual cue to look at your code again (generally,
they're only used for interfacing to legacy code). That's why
BOOST_SMART_PTR_CONVERSION is disabled by default (it provides an implicit
"get()", removing the visual cue).

> Yes, I'm using MSVC. Why won't it compile this? Is the problem the
template
> constructor?

There's a fix in the works. It was decided that MSVC wasn't too broken to
handle this. In the meantime, you can use the smart_ptr.hpp that was posted
to the list today.

In the case of a compiler that doesn't support template members, you have to
do the assignment by hand (which is messy, but no-one's thought of a way to
clean it up yet). With auto_ptr, you do that by
"v0.push_back(v1[0].release())", but with shared_ptr, you would have to:
    v0.push_back(0);
    v0[0].px = v1[0].px;
    ++*(v0[0].pn = v1[0].pn);

        -Steve

P.S. Here's some online references for dealing with smart pointer conversion
issues; it takes a *lot* of thinking to figure out all the various problems
(at least it did me :)

. My web page, where I *try* to explain everything clearly (if you look at
this, let me know how I can make it more clear) (for the problem above, skip
to the section "Allowing Implicit Underlying Pointer Conversions"):
  http://my.voyager.net/~shammah/TBA/docs/main/techniques/ref_class.html

. auto_ptr update for Scott Myer's More Effective C++ book (this is more of
a history; be sure to read the original "Fixing auto_ptr" paper by Bill
Gibbons and Greg Colvin at the end of the page -- I didn't get anything
until I stared at it for a looong time) -- also note that the final auto_ptr
here (and in the Standard) is not quite correct:
  http://www.awl.com/cseng/titles/0-201-63371-X/auto_ptr.html

. You could look at the Standard definition for std::auto_ptr, coupled with
the fixes "in the works" at:
  http://anubis.dkuug.dk/JTC1/SC22/WG21/docs/lwg-active.html#127


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