 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Terry G Guest
|
Posted: Tue Nov 28, 2006 10:10 am Post subject: Virtual Ctor Idiom and auto_ptr |
|
|
In the FAQ, the virtual constructor idioms, create() and clone(), use raw
pointer return values.
Wouldn't it be better if these returned auto_ptr's instead?
But then covariant return types can't be exploited.
Here's some sample code.
Note that the use of clone() in main() is difficult to upcast.
I suppose that if one is using clone() then polymorphic behavior is probably
desired, so the upcast typically isn't necessary.
terry
#include <iostream>
#include <memory>
#include <cassert>
#include <typeinfo>
class Base {
private:
int aBaseMember;
public:
std::auto_ptr<Base> create() const {
Base* ptr = doCreate();
assert(typeid(*ptr) == typeid(*this));
return std::auto_ptr<Base>(ptr);
} // create
std::auto_ptr<Base> clone() const {
Base* ptr = doClone();
assert(typeid(*ptr) == typeid(*this));
return std::auto_ptr<Base>(ptr);
} // clone
void print(std::ostream& os) const { doPrint(os); }
virtual ~Base() { }
protected:
Base() : aBaseMember(0) { }
Base(const Base& other) { aBaseMember = other.aBaseMember; }
private:
virtual Base* doCreate() const = 0;
virtual Base* doClone() const = 0;
protected:
virtual void doPrint(std::ostream& os) const = 0;
}; // Base
inline
void Base::doPrint(std::ostream& os) const
{ os << "Base(" << aBaseMember << ")"; }
inline std::ostream& operator<<(std::ostream& os, const Base& base) {
base.print(os);
return os;
} // << Base
class Derived: public Base {
private:
int aDerivedMember;
public:
Derived()
: Base()
, aDerivedMember(0)
{ }
Derived(const Derived& other)
: Base(other)
{ aDerivedMember = other.aDerivedMember; }
private:
Derived* doCreate() const { return new Derived(); }
Derived* doClone() const { return new Derived(*this); }
void doPrint(std::ostream& os) const {
os << "Derived(" << aDerivedMember <<"): ";
Base::doPrint(os);
} // doPrint
}; // Derived
int main() {
Derived x;
std::cout << "x=" << x << std::endl;
std::auto_ptr<Base> b = x.clone(); // Easy to use polymorphically.
std::cout << "b=" << *b << std::endl;
// Icky. Is there a better way?
std::auto_ptr<Derived> d(dynamic_cast<Derived*>(x.clone().release()));
std::cout << "d=" << *d << std::endl;
} // main
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
James Kanze Guest
|
Posted: Wed Nov 29, 2006 9:42 am Post subject: Re: Virtual Ctor Idiom and auto_ptr |
|
|
Terry G wrote:
| Quote: | In the FAQ, the virtual constructor idioms, create() and clone(), use raw
pointer return values.
Wouldn't it be better if these returned auto_ptr's instead?
But then covariant return types can't be exploited.
Here's some sample code.
Note that the use of clone() in main() is difficult to upcast.
I suppose that if one is using clone() then polymorphic behavior is probably
desired, so the upcast typically isn't necessary.
|
I forgot to mention this in my first answer, but clone() and
create() typically have a very strict post condition, which must
be met by all derived classes, and so are almost never virtual,
but rather call a private virtual function to do the work, and
then verify the post-condition, i.e.:
Base*
Base::clone() const
{
Base* result = doClone() ;
assert ( typeid( *result ) == typeid( *this ) ) ;
return result ;
}
So covariant return types don't apply anyway.
And of course, if a derived class did want to provide a clone()
which returned a Derived*, it is free to do so. Most of the
time, of course, there's no point in it, but I suppose there are
exceptions, e.g. if the derived class defines some sort of
extended contract.
--
James Kanze (Gabi Software) email: james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Alberto Ganesh Barbati Guest
|
Posted: Thu Nov 30, 2006 5:23 am Post subject: Re: Virtual Ctor Idiom and auto_ptr |
|
|
Maxim Yegorushkin ha scritto:
| Quote: | Alberto Ganesh Barbati wrote:
[]
Returning an std::auto_ptr is better than returning a pointer for two
reasons:
[]
2) it also enforces that, in the sense that the cleanest idiom (i.e.:
hold the result in another auto_ptr) will properly manage custody
automatically, while any other "manual" way of keeping the custody
requires an explicit call to the release() method
Could you post a sample please? The only "manual" thing I could come
with, if I understand you correctly, is the following code, where
release is not necessary:
#include <memory
int* f() { return new int(); }
int main()
{
std::auto_ptr<int> p(new int());
p.reset(f()); // no release call required
}
|
Ehr... this example f() does not *return* an std::auto_ptr... so I don't
understand what is the relationship with what I was saying.
I meant this:
// *returns* an std::auto_ptr
std::auto_ptr<int> f();
void legacy_function_that_takes_custody(int* p);
int main()
{
// idiom 1: automatically transfer custody by copying into
// an std::auto_ptr
std::auto_ptr<int> a = f();
// idiom 2: manually obtain custody by explicitly calling release()
legacy_function_that_takes_custody(f().release());
}
HTH,
Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Terry G Guest
|
Posted: Thu Nov 30, 2006 10:10 am Post subject: Re: Virtual Ctor Idiom and auto_ptr |
|
|
James Kanze wrote:
| Quote: | In the FAQ, the virtual constructor idioms, create() and clone(), use raw
pointer return values.
Wouldn't it be better if these returned auto_ptr's instead?
But then covariant return types can't be exploited.
Here's some sample code.
Note that the use of clone() in main() is difficult to upcast.
I suppose that if one is using clone() then polymorphic behavior is
probably
desired, so the upcast typically isn't necessary.
I forgot to mention this in my first answer, but clone() and
create() typically have a very strict post condition, which must
be met by all derived classes, and so are almost never virtual,
but rather call a private virtual function to do the work, and
then verify the post-condition, i.e.:
Base*
Base::clone() const
{
Base* result = doClone() ;
assert ( typeid( *result ) == typeid( *this ) ) ;
return result ;
}
|
I did do that, but mine returned auto_ptr<Base> instead.
| Quote: | So covariant return types don't apply anyway.
And of course, if a derived class did want to provide a clone()
which returned a Derived*, it is free to do so. Most of the
time, of course, there's no point in it, but I suppose there are
exceptions, e.g. if the derived class defines some sort of
extended contract.
|
Yes, that's better. Derived can "override" create() and clone() without
any
adverse affects.
public:
std::auto_ptr<Derived> create() const { return
std::auto_ptr<Derived>(doCreate()); }
std::auto_ptr<Derived> clone() const { return
std::auto_ptr<Derived>(doClone()); }
I'm still stuck on the "rule" that one must not override a non-virtual
member function.
I spent a day writing a clone_ptr<T> class template, returned instead of an
auto_ptr<T> above.
The copy operation would clone() instead of passing ownership along.
I'm sure I'm not the first with this idea, and since this technique isn't
prevalent, I put it in the e-trash.
Does anyone think a clone_ptr<T> is practical?
terry
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ] |
|
| Back to top |
|
 |
Alf P. Steinbach Guest
|
Posted: Fri Dec 01, 2006 12:36 am Post subject: Re: Virtual Ctor Idiom and auto_ptr |
|
|
* Yechezkel Mett:
| Quote: | Alf P. Steinbach wrote:
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() ); }
};
Why do you need virtualClone()? clone() seems to give everything needed.
|
You're 100% right.
I don't recall why I wrote that (virtualClone) code in the first place:
it should have been removed before I hit "Send".
Sorry 'bout that.
Cheers,
- Alf
--
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! ] |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|