allocate memory of derived class

S

Steven Powers

Imagine the following setup

class Parent
{
virtual void doStuff();
}
class Child : public Parent
{
virtual void doStuff();
}

and this function

bool foo(Parent *p)
{
if(!p)
p = new Parent();
p->doStuff();
}

I would like foo() to take a pointer and if it is null allocate the
memory for the class I pass in.

For example

Child * c = NULL;
foo(c);

would result in a Child() constructor and Child::doStuff() being
called.
The way it is now Parent() and Parent::doStuff() will get called.

How can this be done while keeping foo defined as foo(Parent *p) ????

I've thought of using templates like this:
template<class T>
bool foo(Parent* p)
{
if(!p) p = new T();
p->doStuff();
}

but I am unable to get the correct type from a second templated class
that has been passed T = Child* as its template type.

As a follow up can I get a template value T = Child* and somehow pass
foo T=Child ???
 
S

Salt_Peter

 Imagine the following setup

class Parent
{
virtual void doStuff();} ;

class Child : public Parent
{
virtual void doStuff();

} ;

and this function

bool foo(Parent *p)
{
if(!p)
p = new Parent();
p->doStuff();

}

I would like foo() to take a pointer and if it is null allocate the
memory for the class I pass in.

For example

Child * c = NULL;
foo(c);

would result in a Child() constructor and Child::doStuff() being
called.
The way it is now Parent() and Parent::doStuff() will get called.

How can this be done while keeping foo defined as foo(Parent *p) ????

I've thought of using templates like this:
template<class T>
bool foo(Parent* p)
{
if(!p) p = new T();
p->doStuff();

}

but I am unable to get the correct type from a second templated class
that has been passed T = Child* as its template type.

As a follow up can I get a template value T = Child* and somehow pass
foo T=Child ???

Pay attention, you will learn something today.

You said you don't want to change the function's signature so this
would work dandy except for a few problems, i'll try and point out
those to you below:

template<class T>
void foo(Parent* p)
{
if(!p) p = new T();
p->doStuff();
}

and you call it like so:

foo< Child >(pc);
or
foo< Parent >(pc);

___
Now, the important parts. In this language its bad news to distribute
allocation and deallocation, the above code is the perfect example why
that rule is so important. When you pass pointers like so:

Child* pc = 0;
foo< Child >(pc);

the pointer pc never gets modified in main, only its copy in foo does,
so once foo returns you've got a memory leak. And to compound the
issue, foo's Parent* p is no more and we can no longer release your
allocated Child. So if you were to:

if(!pc)
delete pc;

you are in fact deleting nothing. Hence:

template<class T>
void foo(Parent* p)
{
if(!p) p = new T();
p->doStuff();
delete p; // required
}

Which then brings up another issue. virtual destructors.
Whenever you store derived allocations using a pointer to base, you
must declare you base d~tor virtual or you'll end up only deallocating
a portion of your objects.

class Parent
{
public:
virtual ~Parent()
{
std::cout << "~Parent()\n";
}
virtual void doStuff()
{
std::cout << "Parent::doStuff()\n";
}
};

test it, try the d~tor without 'virtual' and delete Parent* p = new
Child.

To solve the original problem involving distributed allocations, you
can pass a pointer by reference, use a smart pointer or some form of
factory that manages allocations and deallocations for you.
If Child is copyable and assigneable, std::vector< Child > or
std::deque< Child > would be the perfect solution. A factory composed
of std::vector< Parent* > would do nicely too.
 
A

acehreli

bool foo(Parent *p)
{
if(!p)
p = new Parent();
p->doStuff();

}

I would like foo() to take a pointer and if it is null allocate the
memory for the class I pass in.

Can it be done at a higher level? Because such side effects make the
code more complicated.
For example

Child * c = NULL;
foo(c);

would result in a Child() constructor and Child::doStuff() being
called.
The way it is now Parent() and Parent::doStuff() will get called.

How can this be done while keeping foo defined as foo(Parent *p) ????

I may be missing something, but isn't this what you want?

bool foo(Parent *p)
{
if(!p) {
p = new Child();
}

p->doStuff();
}

Of course 'p' is being leaked there as was in your original
function. :)

Ali
 
S

Salt_Peter

Pay attention, you will learn something today.

You said you don't want to change the function's signature so this
would work dandy except for a few problems, i'll try and point out
those to you below:

template<class T>

should really be:
 
S

Salt_Peter

I guess I'll have to go through the C++ standard and change every
template declaration to use "typename" instead of "class".

There is no difference between typename and class - the standard
states something like 'no semantic difference'. Not sure this is the
appropriate place or time for that discussion, anywhooo.

The comment was obviously one based on style. Note that not all
template parameters are actual types.

Stroustrup says somewhere:

template<class T> void foo(T& v)
{
typename T::iterator i = v.begin();
}

disambiguates statements, etc.
 
M

Maxim Yegorushkin

I guess I'll have to go through the C++ standard and change every
template declaration to use "typename" instead of "class".

This is a style thing. Some people prefer "typename" for unfathomable
reasons, and right-thinking programmers use "class".

I agree with you. "class" is preferable for pragmatic reasons: easier
to type, occupies less real estate in the source files and means the
very same thing in this context.
 
J

James Kanze

Pay attention, you will learn something today.
You said you don't want to change the function's signature

Which is, in some ways, a contradiction in terms. He wants the
function to depend on the type passed in, without passing in the
type. The obvious solution for the function to depend on the
type is to pass in the type, e.g.:

template< typename T >
bool foo( T* p ) ...

Of course, this doesn't solve the general problem: what to do if
he wants to call the function with "foo( NULL )".
so this would work dandy except for a few problems, i'll try
and point out those to you below:
template<class T>
void foo(Parent* p)
{
if(!p) p = new T();
p->doStuff();
}
and you call it like so:
foo< Child >(pc);
or
foo< Parent >(pc);
Now, the important parts. In this language its bad news to
distribute allocation and deallocation,

Which is simply false. The rule is almost the opposite: if you
don't distribute allocation and deallocation, you shouldn't be
using dynamic allocation to begin with. The most important
single reason for using dynamic allocation is because you need
explicit deallocation, elsewhere in the program.

His case is fairly special (so special that I've never seen it
in 20 years of C++). (But I suspect that he's not described his
problem in enough detail.)
the above code is the perfect example why that rule is so
important. When you pass pointers like so:
Child* pc = 0;
foo< Child >(pc);
the pointer pc never gets modified in main, only its copy in
foo does, so once foo returns you've got a memory leak.
And to compound the issue, foo's Parent* p is no more and we
can no longer release your allocated Child. So if you were to:
if(!pc)
delete pc;
you are in fact deleting nothing. Hence:
template<class T>
void foo(Parent* p)
{
if(!p) p = new T();
p->doStuff();
delete p; // required
}

Which will wreck havoc if he calls the function with a pointer
allocated elsewhere (or pointing to a local object). What he
needs is some sort of manager class:

template< typename T >
class PtrManager
{
public:
PtrManager( Parent* p )
: myPtr( p == NULL ? new T : p )
, myIsOwned( p == NULL )
{
}

~PtrManager()
{
if ( myIsOwned ) {
delete p ;
}
}

Parent* operator->() const
{
return myPtr ;
}

private:
Parent* myPtr ;
bool myIsOwned ;
} ;

This will also save him if p->doStuff() throws.
Which then brings up another issue. virtual destructors.
Whenever you store derived allocations using a pointer to
base, you must declare you base d~tor virtual or you'll end up
only deallocating a portion of your objects.

No, you'll end up with undefined behavior, which is worse. It
may work, it may seem to work, but leak memory, it may crash
immediately, it may corrupt the free space arena, causing a
crash in some totally unrelated code, or it may do just about
anything else.
class Parent
{
public:
virtual ~Parent()
{
std::cout << "~Parent()\n";
}
virtual void doStuff()
{
std::cout << "Parent::doStuff()\n";
}
};
test it, try the d~tor without 'virtual' and delete Parent* p
= new Child.
To solve the original problem [...]

We have to know what the original problem really was:). (I
wonder, for example, if he didn't think that his allocation
actually did modify the original pointer.)
 
J

James Kanze

I agree with you. "class" is preferable for pragmatic reasons:
easier to type,

Funny, I don't find either easier to type than the other.
occupies less real estate in the source files

Which means?
and means the very same thing in this context.

To the compiler. To the human reader, perhaps not.

I use typename here, because it says what I mean. Literally,
both to the human reader and to the compiler.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,586
Members
45,086
Latest member
ChelseaAmi

Latest Threads

Top