Re: Virtual Ctor Idiom and auto_ptr
* Greg Herlihy:
It seems to be that if clone() is going to force an auto_ptr upon its
callers, that the auto_ptr returned should - at the very least - be the
right type:
class Derived
{
public:
std::auto_ptr<Derived> clone() const;
...
};
After all, since Base::clone() is not declared virtual,
Derived::clone() can return whatever it likes.
Of course the caller is still left holding the auto_ptr. So the
question is: what is wrong with letting the caller decide what they
want to do with the returned pointer? The caller can assign it to an
auto_ptr on their own, it is not anything that Base or Derived must do
for them. Nor is it anything that Base or Derived should do - if it is
against the caller's wishes.
It can't be against the caller's wishes: with std::auto_ptr the caller
merely has to express the wish explicitly (like, a release() call) if
the wish is to e.g. leak memory.
std::auto_ptr expresses transfer of ownership in the class' interface code.
Expressing things directly in code is nearly always superior to
expressing it in comments (because the compiler can't check comments for
correctness, and they're frequently misleading and outdated), which in
turn is nearly always better than expressing it implicitly via the
programmer's (possible) understanding (which is often plain wrong) and
attention to detail in client code (which is often lacking, to wit, the
large percentage of programming work that is plain "maintenance").
So std::auto_ptr is indicated, at least until C++0x.
Then there is the issue of covariance.
When using std::auto_ptr as return type, the type-specific publicly
available clone() shouldn't be virtual, as you noted, because the client
code should have available the most specific kind of pointer possible so
as to avoid unnecessary client code downcasts (always undesirable).
With that, the code looks like this (off the cuff):
class Base
{
private:
virtual Base* cloneImpl() const
{ return new Base( *this ); }
public:
typedef std::auto_ptr<Base> AutoPtr;
virtual ~Base() {}
virtual AutoPtr virtualClone() const
{
return AutoPtr( cloneImpl() );
}
AutoPtr clone() const { return AutoPtr( cloneImpl() ); }
};
class Derived: public Base
{
private:
virtual Derived* cloneImpl() const
{ return new Derived( *this ); }
public:
typedef std::auto_ptr<Derived> AutoPtr;
virtual Base::AutoPtr virtualClone() const
{
return Base::AutoPtr( cloneImpl() );
}
AutoPtr clone() const { return AutoPtr( cloneImpl() ); }
};
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]