Sign in to follow this  

c++ memory question

This topic is 3629 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm in the beginning stages of learning C++ as I'd like to be able to use SDL for game development. I have a question about memory usage in C++ and when I need to be concerned with memory leaks. Is it true that the only time I need to use delete is when a pointer is created using new? Are there any other instances where I would need to use delete? Is there garbage collection in C++? Or will I need to NULL out any variables I use to avoid memory leaks? Anything else I should be aware of that I might have missed? Thanks for any help you can provide?

Share this post


Link to post
Share on other sites
Quote:
Original post by ponyboy32
Is it true that the only time I need to use delete is when a pointer is created using new? Are there any other instances where I would need to use delete?

Is there garbage collection in C++? Or will I need to NULL out any variables I use to avoid memory leaks?



There is no standard 'built-in' functionality for garbage collection in C or C++. You are basically on your own for making sure to do it properly. However, there are techniques (Smart Pointers) and 3rd party libraries which can help manage the life time of dynamically allocated memory. But its up to you to wisely ensure memory allocation and destruction is handled properly.

No, setting a dynamically allocated object to NULL will not free it from memory. You must always use the 'delete' keyword on any dynamically created memory. When I say dynamically created memory, I am refering to any memory that was allocated with the 'new' keyword. If you did not allocate the memory with the new keyword, you should never attempt to delete it.

The purpose for setting a variable to NULL, is so that you know it does not contain a pointer. A valid pointer will never be the memory address 0. For instance, we have some constant NULL defined to be the value 0, and a hypothetical class object named 'CMyObj' that defines a 3D Model. We could to the following to make sure our variable has been correctly allocated.

#define NULL 0

// Attempt to allocate a new instance of the object.
CMyObj* model = new CMyObj();

// Check to see the if model contains a valid pointer.
if (model != NULL)
model->setTransform(100, 100, 100);
else
// Something bad happened... We should probably do some error handling.


- Bill

Share this post


Link to post
Share on other sites
Quote:
Original post by ponyboy32
I'm in the beginning stages of learning C++ as I'd like to be able to use SDL for game development.

I feel it worth mention that there are SDL bindings for many higher level languages such as C# which are likely going to be much less painful than using C++.

Quote:
Is it true that the only time I need to use delete is when a pointer is created using new?

Yes.
Quote:
Are there any other instances where I would need to use delete?

No, but you might have to call similar cleanup functions. For example, you should use SDL_FreeSurface on any SDL_Surfaces you created with SDL_CreateSurface (this does NOT include the screen surface that SDL_SetVideoMode returns).

Quote:
Is there garbage collection in C++? Or will I need to NULL out any variables I use to avoid memory leaks?

There is no GC in C++ -- avoiding memory leaks is done by delete-ing every new-ed object, delete[]ing every new[]ed array, etc. -- or better yet, automating the task with a smart pointer, which brings a lot of the benifits of GC (e.g. automating much of the task of cleanup) to non-GCed languages.

The C++ standard library contains one smart pointer class: std::auto_ptr
Also of worthy mention: Boost's Smart Pointers Library




Quote:
// Attempt to allocate a new instance of the object.
CMyObj* model = new CMyObj();

// Check to see the if model contains a valid pointer.
if (model != NULL)


This is wrong -- new will throw an exception (std::bad_alloc) on failure, the C++ standard mandates it cannot return NULL. If you want to use NULL to check for the success of an allocation, you must use it's nothrow variant:

CMyObj* model = new (std::nothrow) CMyObj();

Cavet #1: This will not prevent CMyObj from throwing from it's constructor, however.
Cavet #2: VS6.0 and earlier predate the C++ standard, and as one might expect, don't really conform to it as a result.

Share this post


Link to post
Share on other sites
Also important to point out that NULLing out a variable does absolutely nothing in C or C++ other than modify that variable. The memory does not get freed by setting a pointer to NULL. Doing that will actually create a memory leak, not fix one.

-me

Share this post


Link to post
Share on other sites
Whenever you declare a variable, especially a pointer, initialize it.

CObj * p;

...
...

if (p != NULL) {
// we're fine, P isn't NULL
}


The above code will crash on first run. If you're very lucky. Otherwise, it may happen to have had the value of 0/NULL by coincidence, and your application will happily run along.

Either of these works:
CObj * p = NULL; 
CObj * p(NULL);


Quote:
Is it true that the only time I need to use delete is when a pointer is created using new? Are there any other instances where I would need to use delete?


You clean up your mess. Whatever you allocate, you release. Things includes stuff allocated with new, new[], malloc, various other API calls, or anything else. Unless you have a 100% guarantee that something will be released automatically, then it won't be.

Memory management is why C++ is hard, and almost impossible to get right. Later, there's always RAII, which makes most of the resource management somewhat simple.

Share this post


Link to post
Share on other sites
Thanks for the answers guys, that helps a lot. While I would love to learn C++, I hesitate because I've never learned a language where I had to be so careful about memory.

As far as the higher level language bindings to SDL (SDL.NET I believe for C#) I've looked into those, but was weary of using it because I'm not sure if C# is truly cross-platform? Also, having to distribute the .NET runtime with anything I create is little bit of a turnoff also.

Share this post


Link to post
Share on other sites
Quote:

I've looked into those, but was weary of using it because I'm not sure if C# is truly cross-platform? Also, having to distribute the .NET runtime with anything I create is little bit of a turnoff also.

In some respects, you could consider C# more cross-platform. But that's largely splitting hairs. It is sufficiently cross-platform to be usable, although perhaps not for SDL - the various managed wrappers for SDL may rely on some System.Windows.Forms stuff, which is nonstandard and thus not as well implemented on other platforms.

Distributing the runtime isn't a big deal -- it's not like you don't distribute the CRT with native apps (either as a DLL or statically linked to the application).

Share this post


Link to post
Share on other sites
Quote:
Original post by ponyboy32
As far as the higher level language bindings to SDL (SDL.NET I believe for C#) I've looked into those, but was weary of using it because I'm not sure if C# is truly cross-platform?

It is. See the mono project.

Quote:
Also, having to distribute the .NET runtime with anything I create is little bit of a turnoff also.

You're already redistributing SDL, and probably other supporting libraries (e.g. the CRT), whereas the likes of Vista already comes with .NET 3.0 installed. Understandable kneejerk reaction, but it's worth mentioning it's probably not as big an issue as one might first think.

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
...new will throw an exception (std::bad_alloc) on failure, the C++ standard mandates it cannot return NULL. If you want to use NULL to check for the success of an allocation, you must use it's nothrow variant:

CMyObj* model = new (std::nothrow) CMyObj();

Cavet #1: This will not prevent CMyObj from throwing from it's constructor, however.
Cavet #2: VS6.0 and earlier predate the C++ standard, and as one might expect, don't really conform to it as a result.

I actually did NOT know this! I've been doing NULL checks for no reason at all.

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
This is wrong -- new will throw an exception (std::bad_alloc) on failure, the C++ standard mandates it cannot return NULL. If you want to use NULL to check for the success of an allocation, you must use it's nothrow variant:

CMyObj* model = new (std::nothrow) CMyObj();

Cavet #1: This will not prevent CMyObj from throwing from it's constructor, however.
Cavet #2: VS6.0 and earlier predate the C++ standard, and as one might expect, don't really conform to it as a result.



Your right. I've done most of my C++ coding with VS 6.0, therefore I missed this detail. After doing a quick google search, I found a great article detailing how 'new' worked in VS 6.0 and below and how it currently functions in VS .NET. If anyone is interested, it is located here:

http://msdn.microsoft.com/msdnmag/issues/03/09/LegacySTLFix/default.aspx


However, as someone else noted, it is always a good idea to intialize pointer variables to NULL. Likewise, it is a good idea to set a pointer variable to a NULL value once the data it points to has been deleted. That way you can ensure the pointer variable actually contains a pointer to allocated data.

Share this post


Link to post
Share on other sites
Quote:
Original post by Billr17
Likewise, it is a good idea to set a pointer variable to a NULL value once the data it points to has been deleted. That way you can ensure the pointer variable actually contains a pointer to allocated data.
Well, not exactly - the fact that a pointer is non-null doesn't necessarily mean that it can be safely dereferenced.

Of course, this is yet another good reason to use smart pointers where appropriate (as you suggested in your earlier post).

Share this post


Link to post
Share on other sites
Quote:
Original post by Palidine
Also important to point out that NULLing out a variable does absolutely nothing in C or C++ other than modify that variable. The memory does not get freed by setting a pointer to NULL. Doing that will actually create a memory leak, not fix one.

-me


Potentially cause one, anyway. It's equivalent to closing your eyes and expecting whatever you were looking at to cease to exist.

Share this post


Link to post
Share on other sites
Quote:
Original post by Billr17

#define NULL 0



This is a nitpick, but applicable to the original poster who is just learning C++ and probably wants to gain good habits: Don't use NULL. Sometimes it is carried over from C, but it really doesn't belong in C++. For modern C++ code, just use the literal 0 (zero).

Share this post


Link to post
Share on other sites
Quote:
Original post by onefriedrice
This is a nitpick, but applicable to the original poster who is just learning C++ and probably wants to gain good habits: Don't use NULL. Sometimes it is carried over from C, but it really doesn't belong in C++. For modern C++ code, just use the literal 0 (zero).

NULL is defined in the C++ standard, along with special behavior for pointers that are NULL (it is always safe to delete a NULL pointer). Its value and type is not defined, so #defining NULL to 0 is technically not portable.

NULL will, however, be superceded by a special type - nullptr - in C++0x.

Share this post


Link to post
Share on other sites
Quote:
Original post by Hnefi
Quote:
Original post by onefriedrice
This is a nitpick, but applicable to the original poster who is just learning C++ and probably wants to gain good habits: Don't use NULL. Sometimes it is carried over from C, but it really doesn't belong in C++. For modern C++ code, just use the literal 0 (zero).

NULL is defined in the C++ standard, along with special behavior for pointers that are NULL (it is always safe to delete a NULL pointer). Its value and type is not defined, so #defining NULL to 0 is technically not portable.

NULL will, however, be superceded by a special type - nullptr - in C++0x.


0, as well as being an integer constant, is also the null pointer constant. NULL is #define NULL 0. That said, don't write this yourself. It can be included from one of the standard library headers.

The thing that is undefined is the bit pattern that the pointer constant 0 has. It may not be 00000...etc. This is why it is unsafe to use something like memset or ZeroMemory on a structure with a pointer, even if you memset it to 0.

Share this post


Link to post
Share on other sites
Quote:
Original post by Hnefi
NULL is defined in the C++ standard, along with special behavior for pointers that are NULL (it is always safe to delete a NULL pointer).


Nope [smile] the C++ standard defines special behavior for pointers that are null. NULL itself is mentioned as being an implementation-defined macro for a C++ null pointer constant in 18.1 §4, and a null pointer constant itself is defined by 4.10 §1 as being any constant integer expression which evaluates to zero.

Quote:
Original post by rip-off
0, as well as being an integer constant, is also the null pointer constant. NULL is #define NULL 0.

The thing that is undefined is the bit pattern that the pointer constant 0 has.


Nope [smile] first, 0 is not "the null pointer constant", its just "a null pointer constant". (1-1) or (1*0) or (1>>1) are also null pointer constants by virtue of 4.10 §1. Then, NULL is an implementation-defined macro, which may thus be defined to something else (such as 0L instead of 0). Finally, the pointer constant 0 has no bit pattern: it's just a token in your source code. The null pointer value, unlike a null pointer constant, is unique, exists at runtime, and has an unspecified binary representation.

Share this post


Link to post
Share on other sites

This topic is 3629 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this