C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Virtual Ctor Idiom and auto_ptr

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Terry G
Guest





PostPosted: Tue Nov 28, 2006 10:10 am    Post subject: Virtual Ctor Idiom and auto_ptr Reply with 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.

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





PostPosted: Wed Nov 29, 2006 9:42 am    Post subject: Re: Virtual Ctor Idiom and auto_ptr Reply with quote



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





PostPosted: Thu Nov 30, 2006 5:23 am    Post subject: Re: Virtual Ctor Idiom and auto_ptr Reply with quote



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





PostPosted: Thu Nov 30, 2006 10:10 am    Post subject: Re: Virtual Ctor Idiom and auto_ptr Reply with quote

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





PostPosted: Fri Dec 01, 2006 12:36 am    Post subject: Re: Virtual Ctor Idiom and auto_ptr Reply with quote

* 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
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
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


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.