c++ memory question

Started by
16 comments, last by rip-off 16 years, 3 months ago
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?
Advertisement
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
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.
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
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.
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.
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).
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.
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.
Quit screwin' around! - Brock Samson
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.

This topic is closed to new replies.

Advertisement