(rpg pointer class) concept problem

Pages: 12
look at the code below..I just want to ask***WHY ARE WE USING dynamic memory allocation for MONSTER***.
(THE BOOK SAYS::Also note that when we do create a Monster, dynamic memory must be used so that the system does not
automatically destroy the memory when the function returns).
*************************
Monster* Map::checkRandomEncounter()
{
int
roll = Random(0, 20);
Monster* monster = 0;
if
( roll <= 5 )
{
175
// No encounter, return a null pointer.
return
0;
}
else
if
(roll >= 6 && roll <= 10)
{
monster =new Monster("Orc", 10, 8, 200, 1,
"Short Sword", 2, 7);
cout << "You encountered an Orc!" << endl;
cout << "Prepare for battle!" << endl;
cout << endl;
}
else
if
(roll >= 11 && roll <= 15)
{
monster =new Monster("Goblin", 6, 6, 100, 0,
"Dagger", 1, 5);
cout << "You encountered a Goblin!" << endl;
cout << "Prepare for battle!" << endl;
cout << endl;
}
********************************
Last edited on
This is a question about memory lifetime.

Any local variables declared inside a function exist on the stack memory. This means that when the function returns, the contents of those variables effectively cease to exist (after all the same stack space can now be used for another functions local variables.

In order for data to be returned from a function it must be allocated in such a way that it lives on beyond the exit of the function: from the heap (dynamically allocated memory).

In the case of dynamically allocated memory, we effectively ask a memory manager to give us a pointer to a piece of memory which will exist until we specifically choose to release it (using delete in this case).

So in your example above, we allocate memory for a new instance of the "Monster" class, and return it. It is now the job of whomever receives that memory pointer to free it later (by calling delete).

Hope this helps,
CC


If You want to read something about the stack and the heap follow the link http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/
But in reality all the function would need to do is return a Monster instance and it still works.
However, in the above code, the function occasionally wants to return nothing, and that
is the one and only reason to have the function return a pointer.
This doesn't really apply here... but another reason you might want to return a pointer is for polymorphism:

1
2
3
4
5
6
7
8
Monster* Map::checkRandomEncounter()
{
  if( /*fighting a goblin*/ )
    return new Goblin;
  else if( /*fighting an orc*/ )
    return new Orc;
  /*...*/
}
ok thnx gyz.,, but is jsmith saying null pointer is the only reason,,is the memory lifetime no reason??
Memory lifetime in this case probably isn't a reason because the function can simply return an instance
of the object rather than a pointer to an instance.

I confess, I took my cue that it was about memory lifetime from the comment in the OP:
(THE BOOK SAYS::Also note that when we do create a Monster, dynamic memory must be used so that the system does not automatically destroy the memory when the function returns).


It's true to say that it could return an instance - but obviously that becomes less efficient as the size of the object increases - also polymorphism of the object cannot be achieved using that approach. Depending on the situation it does make sense though.

The rest is open to conjecture, I'm afraid - but I think you now have a full gamut of possibilities :)

Best regards,
CC
Last edited on
WHAT i think is that we could have omitted null pointer like we just dont say return 0;. we say cout<<"no monster "<<endl;.... so dynamic memory is used just to preserve the memory of function...checkRandomEncounter() upto full program...????
This statement:


(THE BOOK SAYS::Also note that when we do create a Monster, dynamic memory must be used so that the system does not automatically destroy the memory when the function returns).


is sort of a non-sequitur and is therefore misleading. I could read this statement to mean that functions may ONLY return
pointers, and that is untrue.


It's true to say that it could return an instance - but obviously that becomes less efficient as the size of the object increases - also polymorphism of the object cannot be achieved using that approach. Depending on the situation it does make sense though.


True enough; another reason to use dynamic allocation is precisely to avoid expensive copies. However, one must
consider the relative expense of copying the object to allocating heap memory. Allocating memory is very expensive,
so it will take a fairly large object or a gazillion copies before I'd consider using a pointer.

The troubles with (raw) pointers are that:
1) They are inherently exception unsafe;
2) They can lead to memory leaks which, in large programs, are very hard to track down.

If pointers were to be used, I would strongly advocate using a std::auto_ptr<> or a boost::shared_ptr<>, depending
upon your needs. Both will help resolve both troubles with raw pointers, but the problem with them (aside from the
fact that boost::shared_ptr<> is fairly heavyweight since it itself requires an internal memory allocation) is that it is yet
more to learn.
This statement:
(THE BOOK SAYS::Also note that when we do create a Monster, dynamic memory must be used so that the system does not automatically destroy the memory when the function returns).
is sort of a non-sequitur and is therefore misleading. I could read this statement to mean that functions may ONLY return pointers, and that is untrue.


I think in the context of the OP, it did make sense since he seemed to be to be asking about the book quote, rather than a generic open question on the subject - but perhaps I misunderstood :)

In any case, I'm was attempting to help the OP without overloading him with too much - I may have misunderstood the purpose of the forums, as I'm quite new to them, so I apologize for any confusion I may have caused.

It seems to me that the book was simply trying to explain about memory lifetime. Whether that is the best way to do it is, I'm sure, very open to debate :)

Best wishes,
CC
Last edited on
No problems. I don't think there was any confusion. I just like to step on soapboxes a lot when it comes to
memory allocation because I work on a project which has a single process consisting of hundreds of thousands
of lines of code and willy-nilly new and deletes of raw pointers where they aren't really necessary (and where
they are, std::auto_ptr<> should be used instead), and whenever there is a proven memory leak (which is
proven by statistical analysis only, by watching memory utilization over literally days of run time) it always takes
weeks and weeks to track it down.

I never use raw pointers to memory that I must manage. If I must dynamically allocate an object
(which isn't terribly often, thanks to the storage capabilities of the STL containers and thanks to making classes
that are cheaply copyable), I store them in std::auto_ptr<> or boost::shared_ptr<> objects. By doing this
not only do I avoid potential memory leaks, but also I get the correct copyability of the pointer / memory
management so that I don't have to write copy constructors or assignment operators. That in an of itself is
a win-win; but perhaps the even larger win is that I have not had to debug a single memory leak in my own
code in 5+ years (encompassing tens of thousands of lines easily).
Definitely agree with you on the use of smart pointers for memory management 100% :)

Without wishing to cause trouble, I'm not a fan of std::auto_ptr, preferring the boost::scoped_ptr pointer in its place - but that's definitely a matter of personal preference. I guess I always found auto_ptr's attitude to lifetime management a little open to abuse, but if you know how to use it in the right way it can be perfectly safe.

Just pity me working back in "C" on an embedded project after 10 years C++! Like you, I had not had to debug memory leaks in a *long* time :(
CC
Last edited on
The problem with std::auto<> is that you cannot put them in some STL containers. The problem with
boost::shared_ptr<> is that it is expensive (an extra memory allocation for the reference count). While
they both manage the pointer they encapsulate, they provide different semantics to the user. It is rarely
a toss-up of which to use because of the semantic differences.

Oh, I do pity you, believe me. I could never go back to C programming now. C++ gives me too much
that I now take for granted.
Sorry - I didn't highlight that last bit very clearly - I was proposing the "scoped_ptr" (not the shared_ptr) from boost to replace the auto_ptr.

The only benefit over the auto_ptr is that you cannot transfer ownership, so if that's important the auto_ptr may still suit. From memory, I think you can get a very similar effect by making an auto_ptr const, but I just don't trust it enough :D Most projects I've worked on just discourage the use of anything other than the boost - so nobody makes the mistake in thinking they can use the auto_ptr that way. The boost::scoped_ptr won't compile if you try and make a make a container use it (no copy constructor/assignment operator).

One thing you may find of interest is the boost pointer containers (http://www.boost.org/doc/libs/1_41_0/libs/ptr_container/doc/ptr_container.html). They were added to boost after the smart pointers, but they have the benefit of behaving (mostly) like their stl equivalents in conjunction with the boost::shared_ptr - but without the overhead of shared_ptr.

C++ gives me too much that I now take for granted.

Indeed - I don't envy me either :)
CC
Last edited on
Yes, I've used the ptr_container library on numerous occasions.
hi gyz.. still i have doubts please clear them!

ok neglect that we have any null case ,. now it says "SO THAT SYSTEM DOES NOT AUTOMATICALLY DESTROY WHEN FUNCTION RETURNS" now IN PLAYER CLASS ALSO HE HAS SAME

DATA(HITPOINTS,ACCURACY etc..) so why this dynnamicc allocation used with monster only and
"" IF SYSTEM DESTROYS MEMORY ... WHY WE WANT TO PRESERVE IT.."
IM CONFUSED AND looking for best answer:)
jsmith,

whenever there is a proven memory leak (which is
proven by statistical analysis only, by watching memory utilization over literally days of run time) it always takes
weeks and weeks to track it down.


Why to keep it running for days just to see if there is a leak? Doesn't Valgrind help there?
Last edited on
Without using dynamic allocation, the data for the monster will go out of scope when the function returns and it will be released back to the system. You need to return a pointer to that data to be able to access it and manually release it back to the system when you don't need it anymore. Where you declared player determines when it will go out of scope. There are many different ways you can do the same thing with similar results.
n4nature:

No, it does not, for reasons I am not at liberty to discuss.
Pages: 12