1

I'm new to C++ and wondering when you should use new and when not, e.g. "int x = 5" or "int * x = new int(5)". I know that new reserves memory in the heap and will thus not be deleted when the block ends, but since the variable the adress is saved in will become unaccessible beyond the block I don't see any benefits.

Example:

if(x) {
 int * z = new int(5);
 // Do something
}
// At this point the 5 is saved somewhere but since z is unaccessible I can't use it.

Add: This question is not duplicated since the other questions do only explain what is the heap while benefits of it are not described.

trincot
  • 317,000
  • 35
  • 244
  • 286
Nicolas
  • 131
  • 2
  • 12
    Simple: Never. :-) – Kerrek SB Dec 18 '15 at 15:14
  • 1
    @KerrekSB I would rather say: Never, unless you really need it. – 463035818_is_not_an_ai Dec 18 '15 at 15:18
  • 2
    @tobi303 I am hard pressed to find a reason in modern C++ where you would need to use it. Unless you are doing something really crazy you should never need to use it. – NathanOliver Dec 18 '15 at 15:21
  • 1
    I use an old C++ learning book (maybe 2006) so that might be why it is still included. – Nicolas Dec 18 '15 at 15:29
  • 4
    @tobi303: I'd say, "if you have to ask, then never". And otherwise you wouldn't be here asking :-) – Kerrek SB Dec 18 '15 at 15:38
  • @Nicolas: In Soviet Russia, `new` is old. – Kerrek SB Dec 18 '15 at 15:38
  • 2
    "Never" is an absurdly misleading comment in the context of this question. You cannot expect a beginner to understand you mean use something like make_unique, but from the point of view of the beginner question make_unique is on the same side of the local vs. new question as new itself is. – JSF Dec 18 '15 at 15:39
  • The simple answer (surprisingly well buried in the official answers) is: Use some kind of heap allocation when you want the object to outlive the scope of the name. That implies you did something that hands off the address of the object to somewhere else, before the name goes out of scope. – JSF Dec 18 '15 at 15:41
  • @KerrekSB completely agree – 463035818_is_not_an_ai Dec 18 '15 at 15:45
  • 4
    @Nicolas even "modern" teachers/books often force their students to learn how to do it the wrong way and then you have to learn that things can be so much easier if you just dont do certain things. imho `new` and pointers are the most prominent representatives of this effect. At some point you have to learn how to deal with them, but it definitely shouldnt be the first thing to see when starting with c++ – 463035818_is_not_an_ai Dec 18 '15 at 15:50
  • 1
    try to use smart pointers and `std::make_shared` – Kryssel Tillada Dec 18 '15 at 15:54
  • @nicolas: the last sentence of the accepted answer to the duplicate question is a succint and correct answer to "when should I allocate an object?" (i.e. when I will later on need a pointer to that object.) It is unlikely to apply to an object as simple as an `int`, but it could happen and the answer is still valid. So I think it is a duplicate. – rici Dec 18 '15 at 16:00
  • I'm rather aghast at the number of people saying "never". Clearly these people have never worked in high performance/numerical computing. When dealing with huge arrays and data structures it's often necessary to explicitly allocate and free memory in order to maintain a predictable memory footprint. The "elegant way" of using new/delete is to keep it confined within the low-level/algorithmic layer of your code or to put it in constructors/destructors. This way, anything that can leak memory is nicely encapsulated. – alfalfasprout Dec 18 '15 at 16:19
  • 2
    @alfalfasprout - We say "never" to newbies because the should not work on the low-level layers of high performance computing. When they get there, they already know that "never" means "hardly ever", and can also tell when it is appropriate. – Bo Persson Dec 18 '15 at 16:25

3 Answers3

5

Use heap allocation when you:

  • Want an object to live past the end of the scope in which it was created
  • Require an array (block of memory) whose size is not known at build time
  • Are creating an object or memory block so large that it will cause this website's namesake (a stack overflow)

Consider the situation where you have a function make that creates an object and returns a pointer to it. If you allocate that object on the stack, it will not exist after the function ends. Allocated on the heap, it exists until the memory is freed with a call to delete, and therefore the caller can safely make use of the object created in make.

(I use the term 'safely' here loosely, since the responsibility for freeing the memory now falls on a different entity than the one that allocated it. Should the new owner of the memory neglect to free it, a memory leak would occur. The solution for this is to use smart pointers to manage your dynamically-allocated memory, specifically unique_ptr).

chili
  • 665
  • 8
  • 20
  • 1
    Your later two reasons are places a beginner should use `std::vector` rather than `new`. That is actually heap allocation in disguise the same way `make_unique` is heap allocation in disguise for your first reason. The comments on the original question show I'm in a minority, but I see a distinction between that first reason and the other two in whether beginners need to start out understanding it is heap allocation (vs. that local `std::vector`) – JSF Dec 18 '15 at 17:58
  • @JSF I'd just like to note that I specifically said 'use heap allocation', and not 'use new'. – chili Aug 31 '16 at 01:31
1

The main characteristics of the C++ heap are that any memory allocated, using new will stay allocated until it is deallocated, using delete and that the heap can be used for large allocations of memory for a large data structure.

The downside of allocating memory with new is that the memory allocation must now be managed because the C++ standard does not have provisions for garbage collection currently (C++17). So if you allocate memory with new, it is your responsibility to make sure that delete is called at some point otherwise you may end up with a memory leak in which the amount of memory your application is using keeps growing larger and larger.

Local variables that are on the C++ stack will be automatically eliminated once the scope where the variable was created is exited. However since the C++ stack normally has much less memory available than the heap, it should not be used for large allocations of memory.

You use the same mechanisms and procedures and coding to make the variable z and the value of that variable available as long as you need it whether z is a pointer or z is not a pointer. The difference is that if you are using a pointer, you must release the memory it is pointing to before it goes out of scope or you must save the pointer value so that you can delete the allocated memory later.

Note that a basic pointer such as int *z that is pointing to a memory area will be eliminated when it goes out of scope just like any other variable however the memory to which it is pointing is not released unless you do an explicit delete before the pointer variable is no longer accessible.

Using variables on the C++ stack provide some benefits. Memory areas are automatically allocated each time the function is called and are automatically deallocated when the function exits. Multiple threads using the same function will each have their own stack space and their use of the function will result in each thread having its own set of stack allocated variables. Using the stack also allows for re-entrant code as well as recursive code so that issues dealing with interrupts and functions which call themselves work out well.

See the following posts for information about recursion and reentrancy.

Understanding how recursive functions work

What exactly is a reentrant function?

Recommended practices for re-entrant code in C, C++

However we come to the problem of data structure size and that some data structures need to have a life cycle which does not depend on one particular block or function. This is where heap allocation using new is useful and actually necessary.

There are several different approaches to using new and heap allocation. The best way is to let the compiler figure it out by using smart pointers. Smart pointers will release allocated memory as part of their destruction processing when the smart pointer variable goes out of scope.

For instance see:

What is meant by Resource Acquisition is Initialization (RAII)?

RAII and smart pointers in C++

Concerning your observation that allocated memory will become "inaccessible" when the pointer containing the address goes out of scope. You are correct and it is your responsibility to ensure that you release the memory with delete before the pointer containing the address goes out of scope. And this is the very problem that smart pointers were invented to solve. Another point is that there is no difference in accessing a variable in either of the following two examples:

if (x) {
    int *z = new(5);
    // .. do things with z or *z
    delete z;
}
// variable z is no longer available

or

if (x) {
    int z = 5;
    // .. do things with z
}
// z is no longer available

In both cases the variable z goes out of scope and can no longer be used. The only difference between using these two different versions of z is you have to dereference the pointer to access the value pointed to in the first version and in the second version you don't.

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
1

Imagine that you are walking across town and have a number of different jobs to do at a number of different buildings. You have a bag that can carry notes in it. And every building also has an empty notepad that you can use, but you aren't allowed to take it out of the building.

It may be that you need to have certain notes that you take with you between jobs. These have to be written down and put inside your bag that goes with you from job to job across town. As you keep adding notes, the bag gets heavier, and it also takes time to put them into and take them out of the bag. (You can only take a note out of the bag briefly to consult it.) You can dump one of these notes at any time, but that also takes a bit of time (and then it's gone forever).

By contrast, some notes are only relevant to the local job/building. For these, it's best to use the building's own local notepad. You can't take these notes with you when you leave the building (the notepad is actually thrown in the trash when you leave), but it's quicker and easier to add and read notes from a building's notepad than it is to use the notes in your carry-everywhere bag (it ALWAYS takes more time getting those notes out of your bag than it does to consult the local notepad).

Sometimes you'll find you want to copy some of your local notes (on a notepad) into your permanent set of notes in your bag, because the information is needed for a later job you'll be doing. And sometimes it turns out to be efficient to copy some of your permanent notes onto the local building notepad when you first enter the building, because if you're going to be there for a while, consulting these notes frequently, it's actually easier to have them on the easy-to-read notepad than to take them out of your bag all the time (remember, you have to move them out of the bag EVERY time you read them).

The bag of permanent notes is the heap. Use it for things you'll want to take with you between jobs, but don't use it if you can use a local notepad just as easily. The local notepad is faster to use, and it doesn't clog up space in your bag. But that also means you can't use it for information you'll need to take between jobs, unless you copy that information into your bag of notes. The local notepad is the stack.

There are actually some complications to this: unknown to you, your permanent bag actually has clever layers inside it that mean that when you pull a note out of it from deep within the bag, it sits closer to the top of the bag for a while so that the next retrieval takes less time. But you can't count on that mechanism: in general, you should assume that it is expensive to take notes out of your bag.

Kaitain
  • 911
  • 12
  • 19