By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,949 Members | 2,038 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,949 IT Pros & Developers. It's quick & easy.

allocate memory of derived class

P: n/a
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 ???
Oct 30 '08 #1
Share this Question
Share on Google+
9 Replies


P: n/a
On Oct 30, 1:23*pm, Steven Powers <StevenAPow...@gmail.comwrote:
*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.

Oct 30 '08 #2

P: n/a
On Oct 30, 11:23 am, Steven Powers <StevenAPow...@gmail.comwrote:
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
Oct 30 '08 #3

P: n/a
On Oct 30, 3:07*pm, Salt_Peter <pj_h...@yahoo.comwrote:
On Oct 30, 1:23*pm, Steven Powers <StevenAPow...@gmail.comwrote:


*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>
should really be:
template< typename 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>
template< typename 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.- Hide quoted text -

- Show quoted text -
Oct 30 '08 #4

P: n/a
On 2008-10-30 18:00:18 -0400, Salt_Peter <pj*****@yahoo.comsaid:
>>
template<class T>

should really be:
template< typename T >
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".

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Oct 30 '08 #5

P: n/a
On Oct 30, 6:43*pm, Pete Becker <p...@versatilecoding.comwrote:
On 2008-10-30 18:00:18 -0400, Salt_Peter <pj_h...@yahoo.comsaid:
template<class T>
should really be:
template< typename T >

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 Tvoid foo(T& v)
{
typename T::iterator i = v.begin();
}

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

--
* Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)
Oct 31 '08 #6

P: n/a
On Oct 30, 11:43*pm, Pete Becker <p...@versatilecoding.comwrote:
On 2008-10-30 18:00:18 -0400, Salt_Peter <pj_h...@yahoo.comsaid:
template<class T>
should really be:
template< typename T >

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.

--
Max
Oct 31 '08 #7

P: n/a
On Oct 30, 9:07 pm, Salt_Peter <pj_h...@yahoo.comwrote:
On Oct 30, 1:23 pm, Steven Powers <StevenAPow...@gmail.comwrote:
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
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.)

--
James Kanze (GABI Software) email:ja*********@gmail.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
Oct 31 '08 #8

P: n/a
On Oct 31, 10:51 am, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
On Oct 30, 11:43 pm, Pete Becker <p...@versatilecoding.comwrote:
On 2008-10-30 18:00:18 -0400, Salt_Peter <pj_h...@yahoo.comsaid:
>template<class T>
should really be:
template< typename T >
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,
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.

--
James Kanze (GABI Software) email:ja*********@gmail.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
Oct 31 '08 #9

P: n/a
James Kanze wrote:
On Oct 31, 10:51 am, Maxim Yegorushkin <maxim.yegorush...@gmail.comwrote:
>On Oct 30, 11:43 pm, Pete Becker <p...@versatilecoding.comwrote:
>>On 2008-10-30 18:00:18 -0400, Salt_Peter <pj_h...@yahoo.comsaid:
>>>>template<class T>
>>>should really be:
template< typename T >

[...]
>>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,

[...]

I use typename here, because it says what I mean. Literally,
both to the human reader and to the compiler.
And then there's the camp that uses 'class' when a template
requires a class and 'typename' otherwise.

Schobi
(yes, I'm a member of that one)
Oct 31 '08 #10

This discussion thread is closed

Replies have been disabled for this discussion.