C++ - freeing dynamic memory

Started by
19 comments, last by Khatharr 10 years, 11 months ago

Hello, I was wondering about freeing the dynamic memory, when the pointer is returned by the function. Let's say I have some piece of code:


int* allocate()
{
     int* ptr=new int[10];
     return ptr;
}

int main()
{
     int* myPointer=allocate();
     delete [] myPointer;
     return 0;
}

Is this ok? I mean, is freeing the memory outside the function ok? It doesn't return exactly the same pointer, but when using "return" it creates a copy of the object, and the returns the copy.. am I correct? So myPointer points on the same place in the memory, even if it isn't "ptr".

Another example:


int* ptr1=NULL, ptr2=NULL, ptr3=NULL, ptr4=NULL;
ptr1=new int;
ptr2=ptr1;
ptr3=ptr2;
ptr4=ptr3;
delete ptr4;

Am I freeing ptr1-3, when freeing ptr4?

Advertisement

Hello, I was wondering about freeing the dynamic memory, when the pointer is returned by the function. Let's say I have some piece of code:


int* allocate()
{
     int* ptr=new int[10];
     return ptr;
}

int main()
{
     int* myPointer=allocate();
     delete [] myPointer;
     return 0;
}

Is this ok? I mean, is freeing the memory outside the function ok? It doesn't return exactly the same pointer, but when using "return" it creates a copy of the object, and the returns the copy.. am I correct? So myPointer points on the same place in the memory, even if it isn't "ptr".

It is perfectly fine. If the returned value is not the same pointer, then you are either mistaken or something is seriously wrong with your compiler. The pointer is (or should be, if it really is different for you) returned by value, so the value of myPointer is main should be the same as the value of ptr in allocate.

Another example:


int* ptr1=NULL, ptr2=NULL, ptr3=NULL, ptr4=NULL;
ptr1=new int;
ptr2=ptr1;
ptr3=ptr2;
ptr4=ptr3;
delete ptr4;

Am I freeing ptr1-3, when freeing ptr4?

Don't think about it as freeing a pointer, but as freeing what the pointer points to. Since all four pointers point to the same thing, then calling delete on one of the four pointers will free the object returned by new.

Once you are done learning how to use dynamic memory allocation and naked pointers, learn how to use standard containers (particularly std::vector) and never do it again. If you are tempted to use dynamic memory allocation and naked pointers in the future when you need polymorphism, learn about standard (in C++11) smart pointers (particularly std::unique_ptr) and continue not doing it.

Generally, you want to enncapsulate the Allocation / Deallocation functionality to the class and make it as automatic as possible.

This means:

1. Have a C-Tor that initializes the Ptr = 0

2. Have a D-Tor that releases the memory by Ptr (you don't even have to check for Ptr == 0, since C++ standard guarantees that). This way, users do not have to worry about leaks - as soon as the class goes out of scope, the allocated memory gets deallocated automatically.

3. Have some Init/Allocate function that handles the low-level details of heap allocation

This way, the pointers are abstracted away from the users of the class. it is a very bad sign, if users of your class would have to remember to clean the heap.

As has been said above, as soon as you learn the above technique, forget about it and go for Smart Pointers, or just Standard Containers.

VladR My 3rd person action RPG on GreenLight: http://steamcommunity.com/sharedfiles/filedetails/?id=92951596

The pattern you are using here however is dangerous for other users of your allocate function as they don't necessarily know you are returning a pointer to an array and thus might mistakenly call "delete myPointer". I know this is just example code but I thought I point this out as it is often something that will cause confusion down the line when dealing with a real version of this pattern.

In all my career there has never really been a reason to write any dynamic allocation code in the games I have written and when it is done it is usually done in manager classes that have control over the lifetime of the objects. Be aware though that console game codebases can pass a lot of naked pointers around and functions often take or return pointers. So understanding of how a pointer and memory works is a pretty important concept to understand.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

I recommend you read this article on C++ memory management. I think it will clarify some of the areas you are struggling with, as well as giving you an idea of how to better manage memory.

This is all good advice, but do make sure that you get comfortable with raw pointers and manual memory management as well. There's all sorts of exciting trouble that you'll miss out on if you don't. (Seriously, though. These are core concepts, so get good with them.)


A pointer is a numeric value that is typically used to store a memory address. It's not the data. It just points to the data.

A pointer is just a number:
char* aPointer = (char*)100;
aPointer -= 50;
std::cout << "The number is " << (int)aPointer << "..." << std::endl;
//Note: Do not do this in production code or the skeleton man will eat you.
You can use a pointer to point to things on the stack:
int ary[] = {5, 6, 7};
int* aPointer = ary;
std::cout << "The array contains: " << std::endl;
std::cout << *aPointer << std::endl;
++aPointer;
std::cout << *aPointer << std::endl;
++aPointer;
std::cout << *aPointer << std::endl;
//Note: You can get fired for that too, unless you have a really good reason.

Or you can use it to point to dynamically allocated memory.

The thing to really grasp in that case is that new and delete are just functions with their own weird syntax. 'new' reserves a block of memory from the heap, and 'delete' releases a block that was previously reserved by 'new'. They're almost completely unrelated to the pointer or pointers that you use to keep track of that block during its lifetime.

One way to think of it is to think of memory as a set of pay lockers. 'new' puts a quarter in the slot (reserves the memory) and you write down the locker number (address) on a note-card (pointer). You can copy that number to another note-card or really do whatever you want with it. Just remember to return the locker key at the end of the day (delete).
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.


int ary = {5, 6, 7};
int* aPointer = &ary;


Both of those lines are wrong. Please, check your code for accuracy before posting it. Just run it through a compiler to make sure you didn't make some mistake, and then copy and paste it here.
I just wanted to give some advice from someone taking a CSCE class at a University right now (Computing Foundations 2).

1: it is very good to learn the standard containers and the smart pointers it can provide. Defintely learn and use then in your personal projects.

Though I would not suggest to just forget about raw pointers after you learn them and never use them again. Honestly I was suggested same thing when I first started learning but IMO it hindered my ability to learn the core concepts. First thig is first learn the core concepts. These teach you internally about each container and allows you I better chose which contained you need at the time.

In my university class when we were taught the basics of some algorithms in some containers and we had to go implement them, we were NOT allowed to use any of the standard containers. When we had to implement a basic linked list, we could not use the std::list. That relies on raw pointers, allocating and deallocating memory on the heap. We had to imement a basic stack, and a basic tree. Now we are implementing a Graph.

They aren't being "mean" and saying the standard library containers suck and you shouldn't use them, but they are teaching us the basics of each one, the basics of how they are done internally. This is all very important. It's important to know how to use and where to use raw pointers. Don't just forget about them and never ever use them again. The core concepts are very important.

Though yes in personal projects I would use smart pointers where I could and of course the containers in the standard library.

I just wanted to point that out. The core concepts of a pointer are very important and I wouldn't suggest that you just forget them after you learn them and never use them again.

int ary[] = {5, 6, 7};
int* aPointer = ary;

I've finished another session at school, and I have my first actual programming class starting next week, so hopefully I'll actually have time for programming again instead of writing essays about how chickens should be raised and similar oh-so-important topics that need to be discussed in order to get a programming degree.

I'm not incredibly optimistic, though, since the class in question is "intro to programming" with no language specified... -.-

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This topic is closed to new replies.

Advertisement