921

I stumbled upon Stack Overflow question Memory leak with std::string when using std::list<std::string>, and one of the comments says this:

Stop using new so much. I can't see any reason you used new anywhere you did. You can create objects by value in C++ and it's one of the huge advantages to using the language.
You do not have to allocate everything on the heap.
Stop thinking like a Java programmer.

I'm not really sure what he means by that.

Why should objects be created by value in C++ as often as possible, and what difference does it make internally?
Did I misinterpret the answer?

Arsen Khachaturyan
  • 6,472
  • 4
  • 32
  • 36
bitgarden
  • 9,749
  • 3
  • 15
  • 24

19 Answers19

1090

There are two widely-used memory allocation techniques: automatic allocation and dynamic allocation. Commonly, there is a corresponding region of memory for each: the stack and the heap.

Stack

The stack always allocates memory in a sequential fashion. It can do so because it requires you to release the memory in the reverse order (First-In, Last-Out: FILO). This is the memory allocation technique for local variables in many programming languages. It is very, very fast because it requires minimal bookkeeping and the next address to allocate is implicit.

In C++, this is called automatic storage because the storage is claimed automatically at the end of scope. As soon as execution of current code block (delimited using {}) is completed, memory for all variables in that block is automatically collected. This is also the moment where destructors are invoked to clean up resources.

Heap

The heap allows for a more flexible memory allocation mode. Bookkeeping is more complex and allocation is slower. Because there is no implicit release point, you must release the memory manually, using delete or delete[] (free in C). However, the absence of an implicit release point is the key to the heap's flexibility.

Reasons to use dynamic allocation

Even if using the heap is slower and potentially leads to memory leaks or memory fragmentation, there are perfectly good use cases for dynamic allocation, as it's less limited.

Two key reasons to use dynamic allocation:

  • You don't know how much memory you need at compile time. For instance, when reading a text file into a string, you usually don't know what size the file has, so you can't decide how much memory to allocate until you run the program.

  • You want to allocate memory which will persist after leaving the current block. For instance, you may want to write a function string readfile(string path) that returns the contents of a file. In this case, even if the stack could hold the entire file contents, you could not return from a function and keep the allocated memory block.

Why dynamic allocation is often unnecessary

In C++ there's a neat construct called a destructor. This mechanism allows you to manage resources by aligning the lifetime of the resource with the lifetime of a variable. This technique is called RAII and is the distinguishing point of C++. It "wraps" resources into objects. std::string is a perfect example. This snippet:

int main ( int argc, char* argv[] )
{
    std::string program(argv[0]);
}

actually allocates a variable amount of memory. The std::string object allocates memory using the heap and releases it in its destructor. In this case, you did not need to manually manage any resources and still got the benefits of dynamic memory allocation.

In particular, it implies that in this snippet:

int main ( int argc, char* argv[] )
{
    std::string * program = new std::string(argv[0]);  // Bad!
    delete program;
}

there is unneeded dynamic memory allocation. The program requires more typing (!) and introduces the risk of forgetting to deallocate the memory. It does this with no apparent benefit.

Why you should use automatic storage as often as possible

Basically, the last paragraph sums it up. Using automatic storage as often as possible makes your programs:

  • faster to type;
  • faster when run;
  • less prone to memory/resource leaks.

Bonus points

In the referenced question, there are additional concerns. In particular, the following class:

class Line {
public:
    Line();
    ~Line();
    std::string* mString;
};

Line::Line() {
    mString = new std::string("foo_bar");
}

Line::~Line() {
    delete mString;
}

Is actually a lot more risky to use than the following one:

class Line {
public:
    Line();
    std::string mString;
};

Line::Line() {
    mString = "foo_bar";
    // note: there is a cleaner way to write this.
}

The reason is that std::string properly defines a copy constructor. Consider the following program:

int main ()
{
    Line l1;
    Line l2 = l1;
}

Using the original version, this program will likely crash, as it uses delete on the same string twice. Using the modified version, each Line instance will own its own string instance, each with its own memory and both will be released at the end of the program.

Other notes

Extensive use of RAII is considered a best practice in C++ because of all the reasons above. However, there is an additional benefit which is not immediately obvious. Basically, it's better than the sum of its parts. The whole mechanism composes. It scales.

If you use the Line class as a building block:

 class Table
 {
      Line borders[4];
 };

Then

 int main ()
 {
     Table table;
 }

allocates four std::string instances, four Line instances, one Table instance and all the string's contents and everything is freed automagically.

Community
  • 1
  • 1
André Caron
  • 41,491
  • 10
  • 58
  • 117
  • 64
    +1 for mentioning RAII at the end, but there should be something about exceptions and stack unwinding. – Tobu Jun 28 '11 at 18:36
  • 8
    @Tobu: yeah, but this post is already quite long, and I wanted to keep it rather focused on OP's question. I'll end up writing a blog post or something and link to it from here. – André Caron Jun 28 '11 at 19:18
  • 1
    @André: edit was fun :-). Re "2 widely used memory allocation techniques"... maybe qualify with run-time, else briefly mention global/static variables as being - for better or more-often worse - a 3rd widely used type...? – Tony Delroy Jun 29 '11 at 02:30
  • 1
    You answered this comprehensively, and better than I could've, though @Tony is right. Variables allocated at program start is a third interesting case that's different from either stack or heap allocation. – Omnifarious Jun 29 '11 at 02:35
  • 2
    @Tony, Omnifarious: same thing as with Tobu, static allocation was a bit out of scope for this reply. I wanted to keep this post focused on the OP's question, which boils down "To `new` or not to `new`." – André Caron Jun 29 '11 at 05:33
  • 16
    Would be a great supplement to mention the _downside_ for stack allocation (at least until C++1x) -- you often need to copy things unnecessarily if you're not careful. e.g. a `Monster` spits out a `Treasure` to the `World` when it dies. In its `Die()` method it adds the treasure to the world. It must use `world->Add(new Treasure(/*...*/))` in other to preserve the treasure after it dies. The alternatives are `shared_ptr` (may be overkill), `auto_ptr` (poor semantic for transfer of ownership), pass by value (wasteful) and `move` + `unique_ptr` (not widely implemented yet). – kizzx2 Jun 30 '11 at 12:09
  • 4
    @kizzx2: that issue is already addressed. If the allocated object must escape the lifetime of the current block, then dynamic allocation must be used (even if it's indirect, such as storing a copy in a vector). – André Caron Jul 01 '11 at 13:18
  • 8
    What you said about stack-allocated local variables may be a little misleading. "The stack" refers to the call stack, which stores *stack frames*. It's these stack frames that are stored in LIFO fashion. The local variables for a specific frame are allocated as if they were members of a struct. – someguy Aug 15 '11 at 19:17
  • 8
    @someguy: Indeed, the explanation is not perfect. The implementation has liberty in its allocation policy. However, the variables are required to be initialized and destroyed in a LIFO fashion, so the analogy holds. I don't think it's work complicating the answer any further. – André Caron Aug 15 '11 at 20:09
  • 2
    maybe add a note about [the rule of three](http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)) right before the `Other notes` section? Don't know if that would be contaminating this answer – Default May 24 '12 at 14:17
  • @AndréCaron Can't you work around your first key reason for dynamic allocation by using `char array[variable];`? I think the first key reason should be that the stack is usually limited in size. – onionjake Jul 29 '13 at 14:39
  • 2
    There is another significant possible reason to use dynamic heap memory -- even if the exact size of memory needed is known. An object may simply be so big that the sheer size creates problems for putting it on the stack. Ideally, some code analysis tools may help by warning when a large object is being placed onto stack memory, but the programmer should also keep that issue in mind. – Eric Mar 25 '19 at 18:26
  • in my opinion it is ethical to give an answer like, "if you don't understand how to use the language", rather than give an example like "Line l2 = l1;" if a person wrote a code like that he definitely doesn't understand the language, writing code like that is definitely not the language mistake – ma1169 May 15 '19 at 22:55
  • I read somewhere that using `new` takes around 50 additional instructions than if the memory was placed on the stack. This is becuase the kernel (i.e. OS) has to find a suitable location in the (possibly fragmented) heap and register/record that location in the heap as now being used. In contrast, in Java, `new` always allocates memory on the stack, although the downside is that the stack becomes fragmented and de-fragmenting the stack means moving allocated memory around, which means that Java has to internally use pointers-to-pointers in certain places. – Matthew K. Dec 15 '19 at 18:39
176

Because the stack is faster and leak-proof

In C++, it takes but a single instruction to allocate space -- on the stack -- for every local scope object in a given function, and it's impossible to leak any of that memory. That comment intended (or should have intended) to say something like "use the stack and not the heap".

einpoklum
  • 86,754
  • 39
  • 223
  • 453
DigitalRoss
  • 135,013
  • 23
  • 230
  • 316
  • 4
    Except it isn't. See the example I wrote below -- you can't allocate class state inside a class on the stack; make a mistake there and the stack won't help you. – Charlie Martin Jun 28 '11 at 00:28
  • 22
    "it takes but a single instruction to allocate space" -- oh, nonsense. Sure it takes only one instruction to add to the stack pointer, but if the class has any interesting internal structure there will be a lot more than adding to the stack pointer going on. It's equally valid to say that in Java it takes no instructions to allocate space, because the compiler will manage the references at compile time. – Charlie Martin Jun 28 '11 at 00:33
  • 34
    @Charlie is correct. **Automatic variables are fast and foolproof** would be more accurate. – Oliver Charlesworth Jun 28 '11 at 00:35
  • 29
    @Charlie : The class internals need to be set up either way. The comparison is being made on allocating the space required. – Oliver Charlesworth Jun 28 '11 at 00:36
  • 2
    @Oli: given the simple question, I am afraid that "automatic variable" will not ring any bell in the OP's mind (or those who will stumble upon this question later on). Let us say that stack is used as a colloquialism ? – Matthieu M. Jun 28 '11 at 06:49
  • 4
    @Charlie, please keep in mind the exact original question. Somehow, the OP seemed to know that he was missing a key insight regarding allocation speed and the fundamental reason for the advice. Simple question. Simple answer. Obviously we can cover C++ more comprehensively and with strictly accurate *("automatic variables")* terminology, but that's partly impossible and partly unhelpful right here. – DigitalRoss Jun 28 '11 at 07:00
  • 54
    *cough* `int x; return &x;` – peterchen Jun 29 '11 at 13:29
  • 1
    @peterchen: Heh, si, I knew someone would say that. We cover that in the next class. :-) This one is just about allocation. – DigitalRoss Jun 29 '11 at 19:30
  • 1
    @DigitalRoss: I was actually surprised noone did before :) – peterchen Jun 29 '11 at 20:32
  • 17
    fast yes. But certainly not foolproof. Nothing is foolproof. You can get a StackOverflow :) – rxantos Feb 12 '15 at 06:25
  • 1
    If the stack was foolproof, then Java would have stack allocation! – gexicide Jun 07 '16 at 01:23
  • 9
    @rxantos Nothing is foolproof because no matter how hard you try to make something foolproof, they continuously make better and better fools who will find a way to blow it up anyway :P ;) – BarbaraKwarc Aug 04 '16 at 01:46
  • 1
    Stumbled upon this post, what's with `int x; return &x;` in this context? Why are people talking about this? @peterchen – yuqli Sep 13 '18 at 17:55
  • 2
    @yuqli: A stab at the claim *"the stack is foolproof"* - returning the address of a local variable from a function is a not too uncommon mistake (though often it happens in disguise, not as obvious as I posted). *Using* such a pointer would invoke UB. – peterchen Sep 25 '18 at 11:13
  • @peterchen Got it. Thanks for the clarification. – yuqli Sep 26 '18 at 17:40
  • 2
    @yuqli https://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope – yano Jan 16 '20 at 15:36
  • The C++ language itself has no concept of a stack or a heap, and you are not required to have any of those in an implementation. Please qualify your answer to distinguish between the language and common platforms it is implemented on. – einpoklum Mar 11 '21 at 19:55
113

The reason why is complicated.

First, C++ is not garbage collected. Therefore, for every new, there must be a corresponding delete. If you fail to put this delete in, then you have a memory leak. Now, for a simple case like this:

std::string *someString = new std::string(...);
//Do stuff
delete someString;

This is simple. But what happens if "Do stuff" throws an exception? Oops: memory leak. What happens if "Do stuff" issues return early? Oops: memory leak.

And this is for the simplest case. If you happen to return that string to someone, now they have to delete it. And if they pass it as an argument, does the person receiving it need to delete it? When should they delete it?

Or, you can just do this:

std::string someString(...);
//Do stuff

No delete. The object was created on the "stack", and it will be destroyed once it goes out of scope. You can even return the object, thus transfering its contents to the calling function. You can pass the object to functions (typically as a reference or const-reference: void SomeFunc(std::string &iCanModifyThis, const std::string &iCantModifyThis). And so forth.

All without new and delete. There's no question of who owns the memory or who's responsible for deleting it. If you do:

std::string someString(...);
std::string otherString;
otherString = someString;

It is understood that otherString has a copy of the data of someString. It isn't a pointer; it is a separate object. They may happen to have the same contents, but you can change one without affecting the other:

someString += "More text.";
if(otherString == someString) { /*Will never get here */ }

See the idea?

Nicol Bolas
  • 378,677
  • 53
  • 635
  • 829
  • 1
    On that note... If an object is dynamically allocated in `main()`, exists for the duration of the program, can't be easily created on the stack due to the situation, and pointers to it are passed to any functions that require access to it, can this cause a leak in the case of a program crash, or would it be safe? I would assume the latter, since the OS deallocating all of the program's memory should logically deallocate it, too, but I don't want to assume anything when it comes to `new`. – Justin Time - Reinstate Monica Feb 04 '16 at 19:19
  • 4
    @JustinTime You don't need to worry about freeing memory of dynamically allocated objects which are to stay for the program's lifetime. When a program executes, the OS creates an atlas of physical memory, or Virtual Memory, for it. Every address in the virtual memory space is mapped to an address of physical memory, and when the program exits, all what's mapped to it's virtual memory gets freed. So, as long as the program exits completely, you don't need to worry about allocated memory never being deleted. – Aiman Al-Eryani Feb 08 '16 at 15:44
77

Objects created by new must be eventually deleted lest they leak. The destructor won't be called, memory won't be freed, the whole bit. Since C++ has no garbage collection, it's a problem.

Objects created by value (i. e. on stack) automatically die when they go out of scope. The destructor call is inserted by the compiler, and the memory is auto-freed upon function return.

Smart pointers like unique_ptr, shared_ptr solve the dangling reference problem, but they require coding discipline and have other potential issues (copyability, reference loops, etc.).

Also, in heavily multithreaded scenarios, new is a point of contention between threads; there can be a performance impact for overusing new. Stack object creation is by definition thread-local, since each thread has its own stack.

The downside of value objects is that they die once the host function returns - you cannot pass a reference to those back to the caller, only by copying, returning or moving by value.

val is still with Monica
  • 1,257
  • 2
  • 15
  • 34
Seva Alekseyev
  • 55,897
  • 22
  • 151
  • 252
  • 9
    +1. Re "Objects created by `new` must be eventually `delete`d lest they leak." - worse yet, `new[]` must be matched by `delete[]`, and you get undefined behaviour if you `delete` `new[]`-ed memory or `delete[]` `new`-ed memory - very few compilers warn about this (some tools like Cppcheck do when they can). – Tony Delroy Jun 28 '11 at 01:21
  • 3
    @TonyDelroy There are situations where the compiler can't warn this. If a function return a pointer, it could be created if new (a single element) or new[]. – fbafelipe Jun 27 '12 at 01:30
32
  • C++ doesn't employ any memory manager by its own. Other languages like C#, Java has garbage collector to handle the memory
  • C++ implementations typically use operating system routines to allocate the memory and too much new/delete could fragment the available memory
  • With any application, if the memory is frequently being used it's advisable to pre-allocate it and release when not required.
  • Improper memory management could lead memory leaks and it's really hard to track. So using stack objects within the scope of function is a proven technique
  • The downside of using stack objects are, it creates multiple copies of objects on returning, passing to functions etc. However smart compilers are well aware of these situations and they've been optimized well for performance
  • It's really tedious in C++ if the memory being allocated and released in two different places. The responsibility for release is always a question and mostly we rely on some commonly accessible pointers, stack objects (maximum possible) and techniques like auto_ptr (RAII objects)
  • The best thing is that, you've control over the memory and the worst thing is that you will not have any control over the memory if we employ an improper memory management for the application. The crashes caused due to memory corruptions are the nastiest and hard to trace.
einpoklum
  • 86,754
  • 39
  • 223
  • 453
sarat
  • 9,454
  • 6
  • 38
  • 71
  • 5
    Actually, any language that allocates memory has a memory manager, including c. Most are just very simple, i.e. int *x = malloc(4); int *y = malloc(4); ... first call will allocate memory, aka ask os for memory, (usually in chunks 1k/4k) so that the second call, doesn't actually allocate memory, but gives you a piece of the last chunk it allocated for. IMO, garbage collectors are not memory managers, because it only handles automatic deallocation of the memory. To be called a memory manager, it should not only handle deallocating but also allocating of memory. – Rahly Jun 23 '15 at 22:45
  • 1
    Local variables use stack so the compiler does not emit call to `malloc()` or its friends to allocate the required memory. However, stack cannot release any item within the stack, the only way stack memory is ever released is unwinding from the top of the stack. – Mikko Rantalainen Oct 12 '18 at 07:21
  • C++ doesn't "use operating system routines"; that's not part of the language, it's just a common implementation. C++ may even be running without any operating system. – einpoklum Jul 28 '19 at 20:40
22

Pre-C++17:

Because it is prone to subtle leaks even if you wrap the result in a smart pointer.

Consider a "careful" user who remembers to wrap objects in smart pointers:

foo(shared_ptr<T1>(new T1()), shared_ptr<T2>(new T2()));

This code is dangerous because there is no guarantee that either shared_ptr is constructed before either T1 or T2. Hence, if one of new T1() or new T2() fails after the other succeeds, then the first object will be leaked because no shared_ptr exists to destroy and deallocate it.

Solution: use make_shared.

Post-C++17:

This is no longer a problem: C++17 imposes a constraint on the order of these operations, in this case ensuring that each call to new() must be immediately followed by the construction of the corresponding smart pointer, with no other operation in between. This implies that, by the time the second new() is called, it is guaranteed that the first object has already been wrapped in its smart pointer, thus preventing any leaks in case an exception is thrown.

A more detailed explanation of the new evaluation order introduced by C++17 was provided by Barry in another answer.

Thanks to @Remy Lebeau for pointing out that this is still a problem under C++17 (although less so): the shared_ptr constructor can fail to allocate its control block and throw, in which case the pointer passed to it is not deleted.

Solution: use make_shared.

Community
  • 1
  • 1
user541686
  • 189,354
  • 112
  • 476
  • 821
  • 5
    Other solution: Never dynamically allocate more than one object per line. – Antimony Aug 16 '13 at 04:30
  • 3
    @Antimony: Yeah, it's a lot more tempting to allocate more than one object when you've already allocated one though, compared to when you haven't allocated any. – user541686 Aug 16 '13 at 04:44
  • 1
    I think a better answer is that the smart_ptr will leak if an exception is called and nothing catches it. – Natalie Adams Sep 16 '13 at 04:34
  • 2
    Even in the post-C++17 case, a leak can still happen if `new` succeeds and then the subsequent `shared_ptr` construction fails. `std::make_shared()` would solve that, too – Remy Lebeau Mar 15 '19 at 00:47
  • @RemyLebeau: Great point, but I don't think a `shared_ptr` constructor can fail? – user541686 Mar 15 '19 at 00:59
  • 1
    @Mehrdad the `shared_ptr` constructor in question allocates memory for a control block that stores the shared pointer and deleter, so yes, it can theoretically throw a memory error. Only the copy, move, and aliasing constructors are non-throwing. `make_shared` allocates the shared object inside the control block itself, so there is only 1 allocation instead of 2. – Remy Lebeau Mar 15 '19 at 02:13
  • @RemyLebeau: Oof, thank you for clarifying. I will update the answer. – user541686 Mar 15 '19 at 02:16
  • While this is a subtle and interesting point in pre-2017 C++, it's too far removed from answering OP's question. Despite the high vote count, I suggest you delete this answer, and add it along with a more focused question, e.g. "Why should I avoid using `new` when construction shared pointers?" – einpoklum Jul 28 '19 at 20:43
  • 1
    @einpoklum: I disagree that it's too far removed from the question. – user541686 Jul 28 '19 at 20:53
22

I see that a few important reasons for doing as few new's as possible are missed:

Operator new has a non-deterministic execution time

Calling new may or may not cause the OS to allocate a new physical page to your process this can be quite slow if you do it often. Or it may already have a suitable memory location ready, we don't know. If your program needs to have consistent and predictable execution time (like in a real-time system or game/physics simulation) you need to avoid new in your time critical loops.

Operator new is an implicit thread synchronization

Yes you heard me, your OS needs to make sure your page tables are consistent and as such calling new will cause your thread to acquire an implicit mutex lock. If you are consistently calling new from many threads you are actually serialising your threads (I've done this with 32 CPUs, each hitting on new to get a few hundred bytes each, ouch! that was a royal p.i.t.a. to debug)

The rest such as slow, fragmentation, error prone, etc have already been mentioned by other answers.

Emily L.
  • 5,274
  • 1
  • 32
  • 60
  • 3
    Both can be avoided by using placement new/delete and allocating the memory before hand. Or you can allocate/free the memory yourself and then call the constructor/destructor. This is the way std::vector usually works. – rxantos Feb 12 '15 at 06:40
  • 1
    @rxantos Please read OP, this question is about avoiding unnecessary memory allocations. Also, there is no placement delete. – Emily L. Feb 12 '15 at 16:54
  • @Emily This is what the OP meant, I think: `void * someAddress = ...; delete (T*)someAddress` – xryl669 Jan 16 '18 at 18:44
  • 1
    Using stack is not deterministic in execution time either. Unless you've called `mlock()` or something similar. This is because the system might be running low on memory and there're no ready physical memory pages available for the stack so the OS may need to swap or write some caches (clear dirty memory) to disk before the execution can proceed. – Mikko Rantalainen Oct 12 '18 at 07:23
  • 1
    @mikkorantalainen that's technically true but in a low memory situation all bets are off anyway wrt performance as you are pushing to disk so there is nothing you can do. It doesn't in anyway invalidate the advice to avoid new calls when it is reasonable to do so. – Emily L. Oct 13 '18 at 11:45
  • Doesnt this mean you have to avoid the STL (at least the parts which allocate?) – lalala Jun 26 '19 at 18:22
  • @lalala depends. Most containers for example don't reduce their capacity when they shrink unless explicitly requested so if you're reusing them then that's fine as there is no actual allocations. Also I said avoid, not prohibit. Use your best judgement. – Emily L. Jun 26 '19 at 19:21
  • This is not true generally - and certainly not at the language level. Please qualify this answer to indicate which platforms this is true on (and perhaps which OS kernel versions you're certain exhibit this behavior. – einpoklum Mar 11 '21 at 19:59
  • @einpoklum I see that you seem to be taking issue with many of the answers on this question, answers that are generally correct on the majority of, if not all implementations but not technically mandated in the standard that it be done that way. Going as far as to claim that an answer that points out a legitimate, on-topic problem should be deleted. There's value in understanding, and working around the quirks of the most common implementation strategies even if they're not technically required to do it that way by the standard, because otherwise it's your application that suffers... – Emily L. Mar 15 '21 at 07:26
17

To a great extent, that's someone elevating their own weaknesses to a general rule. There's nothing wrong per se with creating objects using the new operator. What there is some argument for is that you have to do so with some discipline: if you create an object you need to make sure it's going to be destroyed.

The easiest way of doing that is to create the object in automatic storage, so C++ knows to destroy it when it goes out of scope:

 {
    File foo = File("foo.dat");

    // do things

 }

Now, observe that when you fall off that block after the end-brace, foo is out of scope. C++ will call its dtor automatically for you. Unlike Java, you don't need to wait for the GC to find it.

Had you written

 {
     File * foo = new File("foo.dat");

you would want to match it explicitly with

     delete foo;
  }

or even better, allocate your File * as a "smart pointer". If you aren't careful about that it can lead to leaks.

The answer itself makes the mistaken assumption that if you don't use new you don't allocate on the heap; in fact, in C++ you don't know that. At most, you know that a small amout of memory, say one pointer, is certainly allocated on the stack. However, consider if the implementation of File is something like

  class File {
    private:
      FileImpl * fd;
    public:
      File(String fn){ fd = new FileImpl(fn);}

then FileImpl will still be allocated on the stack.

And yes, you'd better be sure to have

     ~File(){ delete fd ; }

in the class as well; without it, you'll leak memory from the heap even if you didn't apparently allocate on the heap at all.

Andrew Edgecombe
  • 35,947
  • 3
  • 32
  • 60
Charlie Martin
  • 103,438
  • 22
  • 180
  • 253
  • 4
    You should take a look at the code in the referenced question. There are definitely lots of things going wrong in that code. – André Caron Jun 28 '11 at 00:13
  • 7
    I agree there's nothing wrong with using `new` *per se*, but if you look at the original code the comment was in reference to, `new` is being abused. The code is written like it was Java or C#, where `new` is used for practically every variable, when things make much more sense to be on the stack. – luke Jun 28 '11 at 00:15
  • 5
    Fair point. But general rules are normally enforced to avoid common pitfalls. Whether this was an individuals weakness or not, memory management is complex enough to warrant a general rule like this! :) – Robben_Ford_Fan_boy Jun 28 '11 at 00:17
  • @Andre, @Luke, the fact that someone misused new doesn't justify a general rule that you shouldn't use new. – Charlie Martin Jun 28 '11 at 00:34
  • 9
    @Charlie: the comment does *not* say you should never use `new`. It says that if you *have* the choice between dynamic allocation and automatic storage, use automatic storage. – André Caron Jun 28 '11 at 00:54
  • 1
    "or even better, allocate your File * as a "smart pointer". If you aren't careful about that it can lead to leaks." - might be better to mention leaks before smart pointers, as you're implying the smart pointers are prone to leaks ;-). More generally, each class should generally handle any internal pointers it needs in such a way that reliable calling code is easy to write. "Tricky" `new`/`delete` code once and encapsulated in the class, simple and typically `new`/`delete`-free code in the many callers. – Tony Delroy Jun 28 '11 at 01:37
  • 2
    @Charlie OK, but we don't need to justify a rule that says "don't use `new` in XYZ situations"; we need to justify a rule that says "do use `new` in ABC situations", because using `new` is harder than just declaring a value. – Karl Knechtel Jun 28 '11 at 02:05
  • 8
    @Charlie: there is nothing wrong with using `new`, but if you use `delete`, you're doing it wrong! – Matthieu M. Jun 28 '11 at 06:51
  • #Matthieu hey, that's funny. Tell another one. – Charlie Martin Jun 28 '11 at 16:56
  • 1
    @Charlie: Matthieu's got a solid point - unless you're actually implementing a smart pointer, then a good option is to use one to automate the memory deallocation so there's no `delete` in your level of code. BTW / pImpl idiom addresses its need beautifully, but a simple `std::string` will be familiar to a larger percentage of C++ programmers and might lend more immediacy and strength in illustating the issue. – Tony Delroy Jun 29 '11 at 03:19
  • @Tony -- SO, if you need to use delete you're using it wrong -- unless it's not. – Charlie Martin Jun 29 '11 at 16:52
  • 3
    @Charlie: exactly :-). "then FileImpl will still be allocated on the stack." – Tony Delroy Jun 30 '11 at 00:51
  • @CharlieMartin: *"or even better, allocate your `File *` as a 'smart pointer'"*... they work in some cases, but smart pointers still have subtle issues when wrapping the output of `new`. See my answer. – user541686 Aug 14 '13 at 21:28
  • `File foo("foo.dat");` would be better – Lightness Races in Orbit Apr 23 '17 at 13:59
16

new() shouldn't be used as little as possible. It should be used as carefully as possible. And it should be used as often as necessary as dictated by pragmatism.

Allocation of objects on the stack, relying on their implicit destruction, is a simple model. If the required scope of an object fits that model then there's no need to use new(), with the associated delete() and checking of NULL pointers. In the case where you have lots of short-lived objects allocation on the stack should reduce the problems of heap fragmentation.

However, if the lifetime of your object needs to extend beyond the current scope then new() is the right answer. Just make sure that you pay attention to when and how you call delete() and the possibilities of NULL pointers, using deleted objects and all of the other gotchas that come with the use of pointers.

Andrew Edgecombe
  • 35,947
  • 3
  • 32
  • 60
  • 9
    "if the lifetime of your object needs to extend beyond the current scope then new() is the right answer"... why not preferentially return by value or accept a caller-scoped variable by non-`const` ref or pointer...? – Tony Delroy Jun 28 '11 at 01:32
  • 2
    @Tony: Yes, yes! I'm glad to hear someone advocating references. They were created to prevent this problem. – Nathan Osman Jun 28 '11 at 23:48
  • 2
    @TonyD ...or combine them: return a smart pointer by value. That way the caller and in many cases (i.e. where `make_shared/_unique` is usable) the callee never need to `new` or `delete`. This answer misses the real points: (A) C++ provides things like RVO, move semantics, and output parameters - which often mean that handling object creation and lifetime extension by returning dynamically allocated memory becomes unnecessary and careless. (B) Even in situations where dynamic allocation is required, the stdlib provides RAII wrappers that relieve the user of the ugly inner details. – underscore_d Jul 30 '16 at 13:11
14

When you use new, objects are allocated to the heap. It is generally used when you anticipate expansion. When you declare an object such as,

Class var;

it is placed on the stack.

You will always have to call destroy on the object that you placed on the heap with new. This opens the potential for memory leaks. Objects placed on the stack are not prone to memory leaking!

Tim
  • 1,254
  • 2
  • 15
  • 27
  • 2
    +1 "[heap] generally used when you anticipate expansion" - like appending to a `std::string` or `std::map`, yes, keen insight. My initial reaction was "but also very commonly to decouple an object's lifetime from the creating code's scope", but really returning by value or accepting caller-scoped values by non-`const` reference or pointer is better for that, except when there's "expansion" involved too. There's some other sound uses like factory methods though.... – Tony Delroy Jun 28 '11 at 01:28
12

One notable reason to avoid overusing the heap is for performance -- specifically involving the performance of the default memory management mechanism used by C++. While allocation can be quite quick in the trivial case, doing a lot of new and delete on objects of non-uniform size without strict order leads not only to memory fragmentation, but it also complicates the allocation algorithm and can absolutely destroy performance in certain cases.

That's the problem that memory pools where created to solve, allowing to to mitigate the inherent disadvantages of traditional heap implementations, while still allowing you to use the heap as necessary.

Better still, though, to avoid the problem altogether. If you can put it on the stack, then do so.

tylerl
  • 28,220
  • 12
  • 76
  • 108
  • You can always allocate a reasonably huge amount of memory and then use placement new/delete if speed is an issue. – rxantos Feb 12 '15 at 06:33
  • Memory pools are to avoid fragmentation, to speed up deallocation (one deallocation for thousands of objects) and to make the deallocation more safe. – Lothar Nov 11 '15 at 21:20
10

I think the poster meant to say You do not have to allocate everything on theheap rather than the the stack.

Basically objects are allocated on the stack (if the object size allows, of course) because of the cheap cost of stack-allocation, rather than heap-based allocation which involves quite some work by the allocator, and adds verbosity because then you have to manage data allocated on the heap.

Khaled Nassar
  • 854
  • 8
  • 21
10

I tend to disagree with the idea of using new "too much". Though the original poster's use of new with system classes is a bit ridiculous. (int *i; i = new int[9999];? really? int i[9999]; is much clearer.) I think that is what was getting the commenter's goat.

When you're working with system objects, it's very rare that you'd need more than one reference to the exact same object. As long as the value is the same, that's all that matters. And system objects don't typically take up much space in memory. (one byte per character, in a string). And if they do, the libraries should be designed to take that memory management into account (if they're written well). In these cases, (all but one or two of the news in his code), new is practically pointless and only serves to introduce confusions and potential for bugs.

When you're working with your own classes/objects, however (e.g. the original poster's Line class), then you have to begin thinking about the issues like memory footprint, persistence of data, etc. yourself. At this point, allowing multiple references to the same value is invaluable - it allows for constructs like linked lists, dictionaries, and graphs, where multiple variables need to not only have the same value, but reference the exact same object in memory. However, the Line class doesn't have any of those requirements. So the original poster's code actually has absolutely no needs for new.

Thomas Berger
  • 1,750
  • 9
  • 26
Chris Hayes
  • 109
  • 4
  • usually the new/delete would be use it when you do not know before hand the size of the array. Of course std::vector hides new/delete for you. You still use them, but trough std::vector. So nowadays it would be used when you do not know the size of the array and want for some reason avoid the overhead of std::vector (Which is small, but still exist). – rxantos Feb 12 '15 at 06:31
  • `When you're working with your own classes/objects` ...you often have no reason to do so! A tiny proportion of Qs are on details of container design by skilled coders. In stark contrast, a depressing proportion _are_ about confusion of newbies who don't know the stdlib exists - or are actively given awful assignments in 'programming' 'courses', where a tutor demands they pointlessly reinvent the wheel - before they've even learned what a wheel is and **why** it works. By promoting more abstract allocation, C++ can save us from C's endless 'segfault with linked list'; please, let's _let it_. – underscore_d Jul 30 '16 at 13:17
  • "_the original poster's use of new with system classes is a bit ridiculous. (`int *i; i = new int[9999];`? really? `int i[9999];` is much clearer.)"_ Yes, it is clearer, but to play devil's advocate, the type isn't necessarily a bad argument. With 9999 elements, I can imagine a tight embedded system not having enough stack for 9999 elements: 9999x4 bytes is ~40 kB, x8 ~80 kB. So, such systems might need to use dynamic allocation, assuming they implement it using alternative memory. Still, that could only maybe justify dynamic allocation, not `new`; a `vector` would be the real fix in that case – underscore_d Oct 27 '18 at 18:20
  • Agree with @underscore_d - that's not such a great example. I wouldn't add 40,000 or 80,000 bytes to my stack just like that. I would actually probably allocate them on the heap (with `std::make_unique()` of course). – einpoklum Jul 28 '19 at 20:46
3

Two reasons:

  1. It's unnecessary in this case. You're making your code needlessly more complicated.
  2. It allocates space on the heap, and it means that you have to remember to delete it later, or it will cause a memory leak.
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Dan
  • 10,845
  • 11
  • 46
  • 75
2

new is the new goto.

Recall why goto is so reviled: while it is a powerful, low-level tool for flow control, people often used it in unnecessarily complicated ways that made code difficult to follow. Furthermore, the most useful and easiest to read patterns were encoded in structured programming statements (e.g. for or while); the ultimate effect is that the code where goto is the appropriate way to is rather rare, if you are tempted to write goto, you're probably doing things badly (unless you really know what you're doing).

new is similar — it is often used to make things unnecessarily complicated and harder to read, and the most useful usage patterns can be encoded have been encoded into various classes. Furthermore, if you need to use any new usage patterns for which there aren't already standard classes, you can write your own classes that encode them!

I would even argue that new is worse than goto, due to the need to pair new and delete statements.

Like goto, if you ever think you need to use new, you are probably doing things badly — especially if you are doing so outside of the implementation of a class whose purpose in life is to encapsulate whatever dynamic allocations you need to do.

klutt
  • 25,535
  • 14
  • 43
  • 72
1

One more point to all the above correct answers, it depends on what sort of programming you are doing. Kernel developing in Windows for example -> The stack is severely limited and you might not be able to take page faults like in user mode.

In such environments, new, or C-like API calls are prefered and even required.

Of course, this is merely an exception to the rule.

Michael Chourdakis
  • 8,819
  • 2
  • 32
  • 61
1

The core reason is that objects on heap are always difficult to use and manage than simple values. Writing code that are easy to read and maintain is always the first priority of any serious programmer.

Another scenario is the library we are using provides value semantics and make dynamic allocation unnecessary. Std::string is a good example.

For object oriented code however, using a pointer - which means use new to create it beforehand - is a must. In order to simplify the complexity of resource management, we have dozens of tools to make it as simple as possible, such as smart pointers. The object based paradigm or generic paradigm assumes value semantics and requires less or no new, just as the posters elsewhere stated.

Traditional design patterns, especially those mentioned in GoF book, use new a lot, as they are typical OO code.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
  • 4
    This is an _abysmal_ answer. `For object oriented code, using a pointer [...] is a must`: **nonsense**. If you are devaluing 'OO' by referring only to a small subset, _polymorphism_ - **also** nonsense: references work too. `[pointer] means use new to create it beforehand`: _especially **nonsense**_: references or pointers can be taken to automatically allocated objects & used polymorphically; _watch me_. `[typical OO code] use new a lot`: maybe in some old book, but _who cares?_ Any vaguely modern C++ eschews `new`/raw pointers wherever possible - _& is **in no way** any less OO by doing so_ – underscore_d Jul 30 '16 at 13:36
0

Many answers have gone into various performance considerations. I want to address the comment which puzzled OP:

Stop thinking like a Java programmer.

Indeed, in Java, as explained in the answer to this question,

You use the new keyword when an object is being explicitly created for the first time.

but in C++, objects of type T are created like so: T{} (or T{ctor_argument1,ctor_arg2} for a constructor with arguments). That's why usually you just have no reason to want to use new.

So, why is it ever used at all? Well, for two reasons:

  1. You need to create many values the number of which is not known at compile time.
  2. Due to limitations of the C++ implementation on common machines - to prevent a stack overflow by allocating too much space creating values the regular way.

Now, beyond what the comment you quoted implied, you should note that even those two cases above are covered well enough without you having to "resort" to using new yourself:

  • You can use container types from the standard libraries which can hold a runtime-variable number of elements (like std::vector).
  • You can use smart pointers, which give you a pointer similar to new, but ensure that memory gets released where the "pointer" goes out of scope.

and for this reason, it is an official item in the C++ community Coding Guidelines to avoid explicit new and delete: Guideline R.11.

einpoklum
  • 86,754
  • 39
  • 223
  • 453
-6

new allocates objects on the heap. Otherwise, objects are allocated on the stack. Look up the difference between the two.

robert
  • 29,284
  • 8
  • 50
  • 70
  • I'm sure the asker knows the difference (although it's not really as simple as that: e.g. creating a `std::vector` uses both stack and heap memory). You've not answered the question actually asked: _why_ we would want to minimise use of `new`. – Toby Speight Feb 05 '21 at 13:44