473,396 Members | 1,990 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

heap vs. stack

Consider the creation of a class library, where the desire is to allow
the user of the library to chain objects together during construction in
a single statement. For example, this statement uses the heap:

topLevelObject = new type1(new type2(new type3(), new type4());

While this example only uses 4 types, in actuality there will object
trees with a much higher count. Some of the types accept abstract
interfaces, and typeinfo must be maintained such that the library can
correctly traverse the object tree. After construction of these object
trees, the user will pass them to another library object, and be done
with it.

Is it best to:

a. Use pointers, and delete pointers automatically in each class
destructor (freeing user from deleting them but preventing them from
keeping a reference)

b. Use pointers, and require user to delete pointers manually (thus
killing the ability to chain the construction since a pointer to each
object now needs to be kept)

c. Use references - though I'm not sure how that would work with
abstract types...how would you pass an inline contructed derived class
reference where the abstract class reference is expected?

My inclination is to use choice a, though I know pointers are not type
safe, and I'm not sure how good of an idea it is to automatically delete
all the objects in the tree.

Thoughts?

Thanks in advance.
Dec 18 '06 #1
9 1761
On Sun, 17 Dec 2006 23:18:25 -0500, Brian Buderman wrote:
Consider the creation of a class library, where the desire is to allow the
user of the library to chain objects together during construction in
a single statement. For example, this statement uses the heap:

topLevelObject = new type1(new type2(new type3(), new type4());
Cplusplus != JAVA

I wouldn't consider this to be good form in C++. It unnecessarily
complicates the code.

I'd design my objects to have small sizeof() values and let the expression
be evaluated on the stack, using copy constructors to supply the
intermediate object values needed.

However, it is 2AM here so I may reconsider later, but right now I don't
think what you are proposing is a good idea.
Dec 18 '06 #2
Brian Buderman wrote:
Consider the creation of a class library, where the desire is to allow
the user of the library to chain objects together during construction in
a single statement. For example, this statement uses the heap:

topLevelObject = new type1(new type2(new type3(), new type4());
This is not safe. Consider what happens if the expression "new type3()"
is evaluated, and then an exception is thrown during the evaluation of
"new type4()". (Hint: memory leak)
>
While this example only uses 4 types, in actuality there will object
trees with a much higher count. Some of the types accept abstract
interfaces, and typeinfo must be maintained such that the library can
correctly traverse the object tree. After construction of these object
trees, the user will pass them to another library object, and be done
with it.
Instead of carrying type information along with it, I suggest looking up
the Visitor pattern. It was conceived to address this recurring problem
of trying to traverse and perform actions on the nodes of a data
structure where the nodes are of varying type.

As for storage, I suggest you make use of auto_ptr. Accept the objects
as auto_ptrs and store them internally that way as well. Be sure you
either disallow or properly implement a copy constructor and operator=.
This can also help with your exception safety problem above. For each
type, add a static function that creates an object of that type and
returns an auto_ptr. Example:

class type3
{
public:
// Note: this can take parameters as necessary.
static std::auto_ptr<type3create() { return new type3() ; }
} ;

Then your tree would be built with something like:

std::auto_ptr<type1topLevelObject =
type1::create(type2::create(type3::create(), type4::create())) ;

Now, by the time "type3::create()" is evaluated, the memory that was
allocated is already being managed by an auto_ptr, so if
"type4::create()" throws an exception, it will be properly destructed.

Hope this helps.

--
Alan Johnson
Dec 18 '06 #3
Alan Johnson wrote:
As for storage, I suggest you make use of auto_ptr. Accept the objects
as auto_ptrs and store them internally that way as well. Be sure you
either disallow or properly implement a copy constructor and operator=.
This can also help with your exception safety problem above. For each
type, add a static function that creates an object of that type and
returns an auto_ptr. Example:

class type3
{
public:
// Note: this can take parameters as necessary.
static std::auto_ptr<type3create() { return new type3() ; }
} ;

Then your tree would be built with something like:

std::auto_ptr<type1topLevelObject =
type1::create(type2::create(type3::create(), type4::create())) ;
I forgot to take into account the pain-in-the-assness of auto_ptr when I
suggested this. Since the return value, being temporary, can't bind to
the non-const reference in auto_ptr's constructor, that last line won't
work. So either you'd have to construct it piecemeal:
std::auto_ptr<baset3(type3::create()) ;
std::auto_ptr<baset4(type4::create()) ;
std::auto_ptr<baset2(type2::create(t3, t4)) ;
std::auto_ptr<baset1(type1::create(t2)) ;

or use some other smart pointer like tr1::shared_ptr (or
boost::shared_ptr if your implementation doesn't have tr1).

--
Alan Johnson
Dec 18 '06 #4
Brian Buderman <bu******@cisco.comwrote:
Consider the creation of a class library, where the desire is to allow
the user of the library to chain objects together during construction in
a single statement. For example, this statement uses the heap:

topLevelObject = new type1(new type2(new type3(), new type4());

While this example only uses 4 types, in actuality there will object
trees with a much higher count. Some of the types accept abstract
interfaces, and typeinfo must be maintained such that the library can
correctly traverse the object tree. After construction of these object
trees, the user will pass them to another library object, and be done
with it.

Is it best to:

a. Use pointers, and delete pointers automatically in each class
destructor (freeing user from deleting them but preventing them from
keeping a reference)

b. Use pointers, and require user to delete pointers manually (thus
killing the ability to chain the construction since a pointer to each
object now needs to be kept)

c. Use references - though I'm not sure how that would work with
abstract types...how would you pass an inline contructed derived class
reference where the abstract class reference is expected?

My inclination is to use choice a, though I know pointers are not type
safe, and I'm not sure how good of an idea it is to automatically delete
all the objects in the tree.

Thoughts?
This is strictly an issue of ownership. IMHO, the last object to send a
message to an object should also be the one that destroys it. If the
destroyer is not the same as the creator, then you must use heap ram. As
such, I think (a) above is probably the best choice.

However, there is another school of thought that is equally valid. To
them, the object that creates an object should also be the one that
deletes the object. There is much merit to this idea. It makes memory
management easer in general (though it does make factory classes a
little harder to implement,) and it allows the top level objects to
decide whether heap or stack ram should be used for a particular object.
The only reason I don't like such a scheme is that it requires the
top-level objects to hold many objects that they created but never use
themselves.

BTW, pointers are type safe.
Dec 18 '06 #5

Brian Buderman wrote:
Consider the creation of a class library, where the desire is to allow
the user of the library to chain objects together during construction in
a single statement. For example, this statement uses the heap:

topLevelObject = new type1(new type2(new type3(), new type4());

While this example only uses 4 types, in actuality there will object
trees with a much higher count. Some of the types accept abstract
interfaces, and typeinfo must be maintained such that the library can
correctly traverse the object tree. After construction of these object
trees, the user will pass them to another library object, and be done
with it.

Is it best to:

a. Use pointers, and delete pointers automatically in each class
destructor (freeing user from deleting them but preventing them from
keeping a reference)

b. Use pointers, and require user to delete pointers manually (thus
killing the ability to chain the construction since a pointer to each
object now needs to be kept)

c. Use references - though I'm not sure how that would work with
abstract types...how would you pass an inline contructed derived class
reference where the abstract class reference is expected?

Thoughts?
What about "create inside" interface:

Type1 x;
Type2& t1 = x.CreateType2();
Type3& t2 = t1.CreateType3();
......

and manage resources inside Type1, Type2, Type3... (e.g. use owning
containers to implement them).

Mirek

Dec 18 '06 #6
Alan Johnson <aw***@yahoo.comwrote:
Brian Buderman wrote:
Consider the creation of a class library, where the desire is to allow
the user of the library to chain objects together during construction in
a single statement. For example, this statement uses the heap:

topLevelObject = new type1(new type2(new type3(), new type4());

This is not safe. Consider what happens if the expression "new type3()"
is evaluated, and then an exception is thrown during the evaluation of
"new type4()". (Hint: memory leak)

While this example only uses 4 types, in actuality there will object
trees with a much higher count. Some of the types accept abstract
interfaces, and typeinfo must be maintained such that the library can
correctly traverse the object tree. After construction of these object
trees, the user will pass them to another library object, and be done
with it.

Instead of carrying type information along with it, I suggest looking up
the Visitor pattern. It was conceived to address this recurring problem
of trying to traverse and perform actions on the nodes of a data
structure where the nodes are of varying type.

As for storage, I suggest you make use of auto_ptr. Accept the objects
as auto_ptrs and store them internally that way as well. Be sure you
either disallow or properly implement a copy constructor and operator=.
This can also help with your exception safety problem above. For each
type, add a static function that creates an object of that type and
returns an auto_ptr. Example:

class type3
{
public:
// Note: this can take parameters as necessary.
static std::auto_ptr<type3create() { return new type3() ; }
} ;

Then your tree would be built with something like:

std::auto_ptr<type1topLevelObject =
type1::create(type2::create(type3::create(), type4::create())) ;

Now, by the time "type3::create()" is evaluated, the memory that was
allocated is already being managed by an auto_ptr, so if
"type4::create()" throws an exception, it will be properly destructed.

Hope this helps.
Rather than all that, how about simply using the nothrow version of new
in the OP's line above.
Dec 18 '06 #7
On 18 Dec 2006 04:06:39 -0800, "Mirek Fidler" wrote:
>What about "create inside" interface:

Type1 x;
Type2& t1 = x.CreateType2();
Type3& t2 = t1.CreateType3();
.....
and manage resources inside Type1, Type2, Type3... (e.g. use owning
containers to implement them).
Better known as 'Creator As Sole Owner' pattern:
http://www.ddj.com/184409895

Best wishes,
Roland Pibinger
Dec 18 '06 #8

Roland Pibinger wrote:
On 18 Dec 2006 04:06:39 -0800, "Mirek Fidler" wrote:
What about "create inside" interface:

Type1 x;
Type2& t1 = x.CreateType2();
Type3& t2 = t1.CreateType3();
.....
and manage resources inside Type1, Type2, Type3... (e.g. use owning
containers to implement them).

Better known as 'Creator As Sole Owner' pattern:
http://www.ddj.com/184409895
Thanks.

Mirek

Dec 18 '06 #9
Daniel T. wrote:
Alan Johnson <aw***@yahoo.comwrote:
>Brian Buderman wrote:
>>Consider the creation of a class library, where the desire is to allow
the user of the library to chain objects together during construction in
a single statement. For example, this statement uses the heap:

topLevelObject = new type1(new type2(new type3(), new type4());
This is not safe. Consider what happens if the expression "new type3()"
is evaluated, and then an exception is thrown during the evaluation of
"new type4()". (Hint: memory leak)
>>While this example only uses 4 types, in actuality there will object
trees with a much higher count. Some of the types accept abstract
interfaces, and typeinfo must be maintained such that the library can
correctly traverse the object tree. After construction of these object
trees, the user will pass them to another library object, and be done
with it.
Instead of carrying type information along with it, I suggest looking up
the Visitor pattern. It was conceived to address this recurring problem
of trying to traverse and perform actions on the nodes of a data
structure where the nodes are of varying type.

As for storage, I suggest you make use of auto_ptr. Accept the objects
as auto_ptrs and store them internally that way as well. Be sure you
either disallow or properly implement a copy constructor and operator=.
This can also help with your exception safety problem above. For each
type, add a static function that creates an object of that type and
returns an auto_ptr. Example:

class type3
{
public:
// Note: this can take parameters as necessary.
static std::auto_ptr<type3create() { return new type3() ; }
} ;

Then your tree would be built with something like:

std::auto_ptr<type1topLevelObject =
type1::create(type2::create(type3::create(), type4::create())) ;

Now, by the time "type3::create()" is evaluated, the memory that was
allocated is already being managed by an auto_ptr, so if
"type4::create()" throws an exception, it will be properly destructed.

Hope this helps.

Rather than all that, how about simply using the nothrow version of new
in the OP's line above.
Because nothrow is a false promise. It does not guarantee that no
exceptions will be thrown, only that operator new will not throw
bad_alloc. The constructor of the object being allocated may still
throw exceptions.

--
Alan Johnson
Dec 18 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

14
by: Kevin Grigorenko | last post by:
Hello, I couldn't find an obvious answer to this in the FAQ. My basic question, is: Is there any difference in allocating on the heap versus the stack? If heap or stack implementation is not...
17
by: Jonas Rundberg | last post by:
Hi I just started with c++ and I'm a little bit confused where stuff go... Assume we have a class: class test { private: int arr; };
1
by: Geiregat Jonas | last post by:
I'm reading Eric Gunnerson's book. He is talking about the heap and stack, he says you have 2types, value wich are in the stack or inline or reference types wich are in the heap. I don't get...
2
by: Nick McCamy | last post by:
I have a question related to allocating on the stack. In this program below, are my following assumptions true? - variable a is allocated on the heap since it's static - variable b is...
3
by: nahur | last post by:
why do you need a heap and a stack why not all memory called a heap or call it a stack what is the purpose of having a heap and a stack
9
by: shine | last post by:
what is the difference between a heap and a stack?
24
by: arcticool | last post by:
I had an interview today and I got destroyed :( The question was why have a stack and a heap? I could answer all the practical stuff like value types live on the stack, enums are on the stack, as...
16
by: sarathy | last post by:
Hi all, I need a few clarifications regarding memory allocaion in C++. I apologize for the lengthy explanation. 1. In C++, Objects are allocated in heap. What does heap refer to? Is it an area...
53
by: fdmfdmfdm | last post by:
This is an interview question and I gave out my answer here, could you please check for me? Q. What are the memory allocation for static variable in a function, an automatic variable and global...
9
by: Roman Mashak | last post by:
Hello, I'm confused about heap and stack memories management in C language. Most books explain that local stack variables for each function are automatically allocated when function starts and...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.