20

I just had a quick question about how stack variables versus heap variables work. As I understand it, stack variables are variables that after functions return will be deleted, and heap variables are persistent. But what I'm really confused about is how to allocate heap variables inside functions:

int MyObject::addObject(const char* a){
    MyObject newObject(a);
    return 0;
}

Say that I have a constructor for MyObject that is newObject(const char * a). Then in this function when it is called, after the return does the newly constructed newObject get deleted? If yes, how can you allocate to the heap within a function then? If not, how do you cleanup your memory later?

Furthermore, what exactly is the role of a destructor and when is it called?

Eitan T
  • 32,660
  • 14
  • 72
  • 109
KWJ2104
  • 1,959
  • 6
  • 38
  • 53
  • Have you considered using std::string instead of char* ? Throwing C memory management into the mix tends to befuddle, your MyObject class now needs to do decide how owns the memory for the pointer and most likely needs to copy the string and a destructor to release it again. Not doing this is a very likely path to failure. – Hans Passant Dec 11 '11 at 23:10
  • 12
    You shouldn't even be thinking about "stack" and "heap". When you drive a car, you don't typically about cylinder cycle patters, do you? The things to understand in C++ are **storage classes** and **object lifetime**: automatic (scoped), dynamic (manual), static (global). – Kerrek SB Dec 11 '11 at 23:15
  • 8
    @Kerrek When new to C or C++, would you disagree that it's good to know the difference between the two? I think that's what OP is getting at here. – MGZero Dec 11 '11 at 23:20
  • 3
    @MGZero: I'd say it's distracting and misleading to even *consider* the two. Those are an implementation detail that you can ponder on a rainy Sunday over coffee, but for the purpose of understanding C++ they're unnecessary clutter and noise... *especially* when you're new and have *so much more* important stuff to learn :-) – Kerrek SB Dec 11 '11 at 23:36
  • 1
    What a coincidence, it is Sunday and it's raining. Coffee is brewing. – Hans Passant Dec 12 '11 at 00:14
  • 2
    @Kerrek SB, strongly disagree. Do you know that the default stack size on 32-bit Windows is 1MB? If the novice doesn't know this, (s)he may think, cool, I'll use stack all the time — but you really shouldn't do this. – ivanzoid Jul 05 '12 at 11:08
  • 1
    @ivanzoid: I'd say that an algorithm which uses that much stack size may have other problems. Sure, there are situations where you just need a local chunk of memory (in which case you should drop-in replace a `std::unique_ptr`), but that should be a rare exception. – Kerrek SB Jul 05 '12 at 14:34
  • 2
    @KerrekSB: I too disagree. These are not implementation details, these are concepts that you have to understand, for the same reasons that Classes and Objects are concepts in an OOP language, and you should understand those as well. If you don't know where your objects are and the lifetime of those, you are not going to be able to write efficient c++ code. Not in the current state the language is at least. There is only so much you can get away by just scratching the surface. – dryajov Jul 06 '12 at 04:48

8 Answers8

16

A constructor for the class MyObject is MyObject(), not newObject(). In your example, newObject is the name of your variable, not the constructor.

To allocate on the heap inside a function, you need to call the new operator:

int MyObject::addObject(const char* a){
    MyObject* newObject = new MyObject(a);
    //newObject is allocated on the heap

    //... Some more code...

    delete newObject;
    //you have to explicitly delete heap-allocated variables
    //if not, you get memory leaks
    return 0;
}

Your code:

MyObject newObject(a);

creates an automatic storage (stack) MyObject called newObject that lives until the scope it was declared in ends - i.e. closing }.

Furthermore, what exactly is the role of a destructor and when is it called?

To clean up memory the class allocated with new or new[] (or malloc) and it owns. It is called either when the object goes out of scope for automatic objects, or when you explicitly call delete for dynamic objects.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 1
    So newObject is a pointer that points to a place in memory where some MyObject is stored. So without deallocating the MyObject using the pointer, the object wouldn't go away. If I understand this right, then are you able to pass the newObject pointer to somewhere outside teh function or is that just deleted after function call? – KWJ2104 Dec 11 '11 at 23:21
  • 1
    pedantically, in the code above there is a stack variable of type MyObject*, which is a pointer, pointing to a heap region. the stack variable gets deallocated on return (but you can still return it, because it's returned by value), but the region it points to doesn't. nothing is ever automatically freed which was allocated with `new` – P Varga Dec 12 '11 at 01:00
  • 1
    @Matt the object is not dealocatted unless you explicitly do it. You can of course return the pointer from the function and deallocate it outside, but that needs to be documented so people using the function know the responsabilty of the clean-up lies with them. – Luchian Grigore Dec 12 '11 at 06:05
3
int addObject(const char* a){
    MyObject newObject(a);
    return 0;
}

This code allocates newObject on the stack. It is constructed (MyObject constructor is called on a chunk of stack memory) when entering the function. It's destructed (MyObject destructor called on that instance) when the function returns just before the chunk of memory is popped from the stack.

MyObject *foo =  new MyObject(a);

This code allocates an object on the heap. The constructor is called by the new operator after it's allocated some heap memory. The memory isn't freed and the destructor isn't called until you explicitly say you're done with it with the delete keyword.

delete foo;

This can be anywhere you want in your program.

Pete Fordham
  • 2,278
  • 16
  • 25
  • 2
    That's another question entirely. foo can be managed any way you care to manage it. It's the value of foo that's important and must be preserved until deletion, not the location that it's stored in. You can pass it to functions, return it from functions, store it in a global or whatever. – Pete Fordham Jun 30 '12 at 01:58
3

Stack memory is what you said, but to be more specific, it's memory local to the current scope. Note that depending on what scope you're talking about, this memory could be global or it could be local to a function or class. These are cleaned up once they've gone out of scope.

Heap memory in allocated via the new operator. These will persist in memory even after all pointers pointing to the memory have gone out of scope. You must explicitly release this memory yourself in C++ via delete. Failing to do so will result in a memory leak unless smart pointers are used.

Another thing to note, take the following sample code:

void foo()
{
   int *bar = new int; //creates a pointer to an int on the stack, but initializes an int on the heap
   *bar = 3; //sets the int being pointed to to 3
   delete bar; //deletes the int
   bar = 0; //removes the now invalid reference
}

the pointer itself, bar, is created on the stack. However, the data pointed to by bar. *bar -- yes, the asterisk does make a difference here. It gets you the data pointed to by the pointer -- is on the heap. When foo returns, bar will go out of scope. Had I not called delete, I would have lost access to *bar and would have gotten a memory leak.

For the second question, the role of the dtor is to clean up the object you've constructed. One is provided by default for you, but there are times when you need to write your own. For example, if your class has raw pointers in it, you need to explicitly release them with delete in the dtor. It's called when the object goes out of scope for stack memory and when delete is called for heap memory.

MGZero
  • 5,812
  • 5
  • 29
  • 46
  • So is there any way to allocate pointers onto the heap so that one can reference them later to delete heap objects instead of them going out of scope on function returns? – KWJ2104 Dec 11 '11 at 23:34
  • Sure, you can return the pointer itself. This will give you the memory address it's pointing to, which you can hang to in a pointer in a different scope. And note you don't allocate pointers to the heap (well, you can, but in most cases you don't) you allocate memory for the pointer to point to on the heap. – MGZero Dec 12 '11 at 00:04
2
  • The stack is a an area that the is used in function and method calls. It is basically utilized to store parameters and function local data (among other things involved in the process of calling a function). The stack is a LIFO kind of data structure, meaning that the last thing you put in is the first you get from it.

  • The heap on the other hand is a free store, by that I mean you can get any values from the heap no matter the order it was put in there - this distinction is important.

  • In C++ , every time you call new the object is created on the Heap and a pointer to that object is returned to you, you can then use that pointer to access your object. That applies to both complex objects such as objects from classes you or someone else has created, and built in types, such as int, char, double etc... There is nothing magical with using new, at it's core it simply calls malloc, or some flavor of it depending on the platform, and then calls the constructor for the object. You have to remember to call delete (or delete []p_array_of_object_pointers) for every object created with new.

  • The destructor is nothing more than a function that the language calls on the object when you do a delete my_object_pointer in your code. The destructor gives you a chance of doing some clean up in your code. In languages such as C++, where you have to manage your own resources, you would usually use it to call delete or free on other objects you have allocated on the heap, or closing file handles you've created with fopen or such...

  • Both of this keywords work inside or outside a functions and methods, it does not matter where you call them from, they will always work with the heap. Anything you create without the use of new will end up in some other place, either the static area of the executable or the stack, depending on how and where it is being created.

  • Every time you create an object inside a method or function with the following syntax MyClassType myObject(contructor, arguments); and without the use of new, you are creating it on the stack (unless you declare it as static, which is when it ends up in that static area I mentioned above).

Hope this helps.

dryajov
  • 445
  • 3
  • 13
1

heap allocations are done with the new keyword

C++ has no garbage collection, heap allocations are never automatically freed

you can free them with the delete keyword

you need to keep a pointer for that, for example by returning it from the function, or by assigning it to a global variable

destructors are called on delete and are used to free resources, for example network sockets

so the code would be, for example return new MyObject("foo");

P Varga
  • 19,174
  • 12
  • 70
  • 108
0

How to allocate to heap: use new keyword

How to deallocate from heap: use delete keyword.

To avoid program crashing and memory leaks, each new must have its delete counterpart for the specified object and type.

Destructor is called when object gets deleted regardless of where it was stored(heap, stack, ...)

And here's more specific info about memory: What and where are the stack and heap?

Community
  • 1
  • 1
weggo
  • 134
  • 3
  • 10
0

Use dynamically allocated instances of objects when:

1) The actual type of object is not known at compile time 2) When the number of objects you want to create, is not known at compile time 3) When the (compiler generated) lifetime management of your objects does not meet your needs.

Every object created with new operator, should be freed with delete operator at some time. If you don't, you will have memory leaks, and if you depend on the side effects of the objects destructor, you won't get those side effects and your program may not do what it is desired to do.

When an object is created as a stack variable, the compiler will insert code to call the objects destructor when the object goes out of scope. How does the compiler know what destructor to call? The type of object is known at compile time, so there is only one posibility, only one destructor to call.

If you use 'delete' to destroy an object, the compiler may not be able to tell which destructor to use. The object may be of type 'basic', then the destructor 'basic::~basic()' will be called.

    class basic;
    class derived : public basic
    {
           ....
           ~derived();
    }

    basic *l = new derived();
    ...
    delete l;

The compiler does not know the actual type of the object is not 'basic' but 'derived'. If however, you declare the destructor of 'basic' to be virtual, the compiler will insert code that consults the objects virtual method table, and the call is redirected to the right destructor (in this case the destructor that destructs on object of type 'derived').

If you are worried about this problem, and if you can, make the destructor 'virtual'.

bert-jan
  • 958
  • 4
  • 15
0

You allocate memory in stack in your example. It's automatic variable and it would be deleted then return happened. If you use new keyword you must provide correct deallocation

MyObject* newObject = new MyObject(a);
Yappie
  • 399
  • 2
  • 8