Skip to main content
gamedev.net
🔒 Locked

Pointers: Beginning to Intermediate

Started by Myopic Rhino Apr 24, 2003 at 2:33 AM 8 replies 1.6k views
Oluseyi
Oluseyi
quote:
From the article:
New and Delete are the number one cause of memory leaks.
No, they're not. Faulty understanding and use of new and delete are the number one and two causes of memory leaks. Here are simple rules of thumb that virtually guarantee headache-free dynamic memory management in C++:
  1. If you allocate it, remember to deallocate it. Every new must be matched by a corresponding delete, and every new [] (the two operators are not the same form and have different effects) by a corresponding delete [].

  2. Be careful with scope. Dynamic allocations cross scope boundaries, so if you allocate memory in one scope and pass it to an outer one, you need a sure-fire method of deallocating the memory later. Here's an example:
    char * AllocateChars( int size )
    {
    return new char [size];
    }

    Any code that calls AllocateChars is now responsible for deallocating the allocated memory at a latter time, which is so easy to forget to do. The simplest solution is to use some form of smart pointer, like std::auto_ptr or boost::shared_ptr (the latter is much more robust due to its ownership policies, but you can also roll your own with Copy-On-Write semantics for added safety):
    std::auto_ptr< char > AllocateChars( int size )
    {
    return std::auto_ptr< char >( new char [size] );
    }


quote:
The STL library provides solutions to common problems where new and delete are apart of the initial solution.
Such as? I'm sorry if I sound harsh, but I find this statement insufficiently qualified. An example would have been nice so that the statement can be corroborated or more clearly understood.

Otherwise a solid article, with two omissions. The first is the lack of discussion of references, which are a powerful mechanism that eliminate a lot of the programmer responsibility of pointers. The second is the erroneous statement that pointer to member functions must point to static member functions. Pointer to static member functions are simpler to manipulate, but not the only type of pointer to member function by a long shot:
class A
{
void a( void ) { int i = 1 + 2; }
typedef void (*A:: Pmf)( void ); // EDIT: P-smiley
pmf pointer_to_Aa;
};
 
A a;
a.pointer_to_Aa = a.a;

The complexity arises in invoking the member function pointed to. Non-static member function pointer dispatch requires a valid class instance to "hang off of" like so:
a.(*pointer_to_Aa)();  

This complexity makes pointers to non-static member function more unweildly and less inviting to use.


Finally, it's advisable to avoid void pointers as much as possible. Generic systems are better written using C++'s generic programming facilities (templates) despite the code bloat, because they retain all type information internally and ameliorate the possibility of programmer type error, which could hypothetically have severely adverse results.

EDIT:
I should note that while refrences are powerful in C++, they're nowhere near as powerful as they are in other languages. C++ references can not be re-bound, and must be bound at creation (initialized). These limit their use in highly dynamic situations.

[edited by - Oluseyi on April 24, 2003 7:02:00 AM]
Illumini
Illumini
Oluseyi, I do agree with you that the headaches associated with new/delete are avoidable. But a firm grasp on the rules you provide works only in theory. In reality it takes along time programming with new/delete to avoid the myriad of problems you can cause yourself. For the beginer/intermiediate programmer (who this article is aimed at) I feel it gives the accurate portrail of how frustrating new/delete can be at times.

That said I feel new/delete can be used without much of a headache but this only comes with expierence, in my opinion anyway.

[edited by - Illumini on April 24, 2003 4:10:26 PM]
zealouselixir
zealouselixir
quote:

Before you can use a pointer, you have to initialize it. You must set it to point to a valid memory location, otherwise it points to nowhere and that can crash your computer.


Only by a fault in the operating system. The vast majority of the time, it will result in an access violation, causing the program itself to scream and die (unless you handle the exception). Yeah, sure, it''s a colloquial thing, but it''s also misleading.

Also,

enum{
FLAG1, // = 0
FLAG2,
FLAG3,
…
FLAG12, // = 12
};

Still trying to figure that out... 1 = 0, 2 = 1, ..., 11 = 10...
[twitter]warrenm[/twitter]
CaptainJester
CaptainJester
quote:
Original post by Illumini
Oluseyi, I do agree with you that the headaches associated with new/delete are avoidable. But a firm grasp on the rules you provide works only in theory. In reality it takes along time programming with new/delete to avoid the myriad of problems you can cause yourself. For the beginer/intermiediate programmer (who this article is aimed at) I feel it gives the accurate portrail of how frustrating new/delete can be at times.

That said I feel new/delete can be used without much of a headache but this only comes with expierence, in my opinion anyway.



I disagree. When I first learned of new/delete, I started using them right away without difficulty. They have a much easier syntax than malloc/free.



First make it work,
then make it fast.

--Brian Kernighan

"I’m happy to share what I can, because I’m in it for the love of programming. The Ferraris are just gravy, honest!" --John Carmack: Forward to Graphics Programming Black Book
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][
dalleboy
dalleboy
quote:
Original post by Oluseyi
return std::auto_ptr< char >( new char [size] );

That is just bad, std::auto_ptr will do a delete and not a delete [] and thus it will break your own #1 rule. boost::shared_array is a better choice.



Update GameDev.net system time campaign - success at last

[edited by - dalleboy on April 27, 2003 6:43:00 AM]
LessBread
LessBread
It''s good to see your article published.
"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
JGailor
JGailor
Minor point...

  
int array[5] = {1,2,3,4,5}; //initialize array of int values

int* array2[5]; //create an array of pointers to int values

int* pointer = array; //store the pointer to the first element of the array of int values


for(int i = 0; i < 5; i++)
{
array2[i] = ++pointer; // increase the pointer to point to the next address in the array

}

array2[4] = array; //append the address of first ordinal to end of array of addresses




You may want to have your termination condition on the for loop be ( i < 4 ) because the last time through, the pointer is moved off the end of array and just puts garbage into array2[4]. You are just writing over it at the end, but for someone who is a novice, and tries to run through, it may cause some confusion.

Good article though.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.