Boost logo

Boost :

From: Schoenborn, Oliver (Oliver.Schoenborn_at_[hidden])
Date: 2002-10-04 07:58:06


> "Schoenborn, Oliver" <Oliver.Schoenborn_at_[hidden]> wrote in message
> news:35C5DD9F60FED21192B00004ACA6E6C70151C87F_at_nrclonex1.imti.nrc.ca...
> > [...]
> > I would also like to find out. In any case, I have used
> > this technique to get around it:
> > [...]
>
> Oddly enough, gcc gives a more informative message:
>
> warning: conversion to a base class will never use a type conversion
> operator.
>
> I guess that pretty much explains things, and I guess I can understand
> why. I guess that means that if you want implicit
> conversion, you need public inheritance. That doesn't seem so
> bad to me, but maybe others disagree.

I disagree Dave. For one thing, you don't need any inheritance whatsoever to
get implicit conversions. Secondly, I could see why public inheritance would
disallow implicit conversion to the base class, but I fail to see why
NON-public inheritance would. Indeed the conversion is public but the base
is not, so it should be doable. What is just an oversight of the standards?

> > [...]
> > - it prevents the user from passing a non-const smart_ptr<const T>
> > (would be dangerous if allowed)
>
> Well, the conversion operator would be nice here, since we could
> force it to return a ptr<T const> const, if it would let us.
> But simply
> exposing the base class does present a bit of a problem. However,
> in the usage I imagine, it does not:
>
> template <typename T>
> class ptr;
>
> template <typename T>
> class ptr<T const>
> {
> public:
> ptr() { }
> T const* operator->() const { return p_; }
> private:
> ptr(ptr const&);
> T* p_;
> };
>
> template <typename T>
> class ptr : public ptr<T const>
> {
> public:
> ptr() { }
>
> T* operator->() const { return p_; }
> private:
> ptr(ptr const&);
> };
>
> class foo
> {
> public:
> void bar();
> };
>
> void baz(ptr<foo const> const& p)
> {
> p->bar(); // Caught!
> }
>
> int main()
> {
> ptr<foo> p;
> baz(p);
> }
>
> Note to Eric: go ahead and compile this sample. Note that I have made
> ptr<> non-copyable, to demonstrate that the copy c'tor is not called.
>
> It's true that you could accidentally declare:
>
> void baz(ptr<foo const>& p)
> {
> p->bar(); // Caught!
> }
>
> and thereby modify p. However, this is true in general, and
> I don't think it presents a significant risk. This is an interesting
> idiom, and I would like to hear other people's comments on it. Not
> worth the complexity? Hidden problems/risks?

I don't see how it is true in general. If you do the raw pointer equivalent
of the last example, you have

void baz(const foo* p)
{
     p->bar();
     p = ...; // caught for raw pointer!
}

because you rarely pass a pointer by reference. The only time you do is when
you know you will modify it. However, the whole point of constness is to
help you avoid modifying something that shouldn't be modified. So when the
function takes a smart_ptr by reference, you know it will modify it,
otherwise it would take it by const reference. So you've just eliminated a
standard check of constness.

Another reason not to do it is that you can now slice smart_ptr by mistake,
though in this particular case, there is no data in the derived smart_ptr so
you're probably safe, but I'd have to check what the standard says about
that. So problem there is if you ever *have* to add data to the non-const T
version you're breaking a fundamental rule.

Also, (if that weren't enough already) in the full implementation there will
be methods of the base that you want to not have visible. Those methods that
accept a const T, since that equates to conversion from const to non-const.

All in all, it seems to me you have no choice but to use non-public
inheritance, and because the standard doesn't seem to allow implicit
conversion even for such inheritance (though it should AFAICT), you are
forced to have a method that returns a ref to the base, as in my initial
example.

Oliver


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