7

Suppose that you have the following function:

 void doSomething(){
    int *data = new int[100];
 }

Why will this produce a memory leak? Since I can not access this variable outside the function, why doesn't the compiler call delete by itself every time a call to this function ends?

jsguy
  • 2,069
  • 1
  • 25
  • 36
  • 1
    you say "variable", the compiler DOES delete the "variable" here, but he doesn't delete the memory where it points, because that's what the heap actually is for, at least partially, else you would have to verify that nothin points to that memory before unallocating it, that's what a "garbage collector" is for – Guiroux Mar 03 '15 at 13:45
  • you are right, but I still don't get why the memory is not deallocated automatically. – jsguy Mar 03 '15 at 13:46
  • You are looking for [garbage collection](http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29). Java does this (more or less). C++ just does things differently, with it's own positives and negatives. – BoBTFish Mar 03 '15 at 13:46
  • 1
    @jsguy: In theory it could be. Some of what was changed in C++11 was to make it at least possible to create a conforming implementation that included a garbage collector. In fact, it doesn't happen because most C++ programmers are not willing to put up with the tradeoffs involved in adding a garbage collector. You can, however, [add on a garbage collector](http://www.hboehm.info/gc/), if you want to badly enough. – Jerry Coffin Mar 03 '15 at 13:49
  • Also keep in mind that the author may not *want* it to be deallocated. Not because he wants to reuse the memory, but because he knows the function will not be called enough that the memory leaks it causes will actually cause a problem, and he doesn't want run time wasted on deallocation. He's probably a pretty bad programmer, to be sure, but one of the core principles of C++ is that you don't pay for what you don't use. – Benjamin Lindley Mar 03 '15 at 14:13
  • There is a mechanism called "Automatic Reference Counting" in some languages (like Objective-C or Swift), in which the compiler *would* handle freeing the allocated memory for you in a similar case. – Michał Ciuba Mar 03 '15 at 14:14

6 Answers6

9

Why will this produce a memory leak?

Because you're responsible for deleting anything you create with new.

Why doesn't the compiler call delete by itself every time a call to this function ends?

Often, the compiler can't tell whether or not you still have a pointer to the allocated object. For example:

void doSomething(){
    int *data = new int[100];
    doSomethingElse(data);
}

Does doSomethingElse just use the pointer during the function call (in which case we still want to delete the array here)? Does it store a copy of the pointer for use later (in which case we don't want to delete it yet)? The compiler has no way of knowing; it's up to you to tell it. Rather than making a complicated, error-prone rule (like "you must delete it unless you can figure out that the compiler must know that there are no other references to it"), the rule is kept simple: you must delete it.

Luckily, we can do better than juggling a raw pointer and trying to delete it at the right time. The principle of RAII allows objects to take ownership of allocated resources, and automatically release them when their destructor is called as they go out of scope. Containers allow dynamic objects to be maintained within a single scope, and copied if needed; smart pointers allow ownership to be moved or shared between scopes. In this case, a simple container will give us a dynamic array:

void doSomething(){
    std::vector<int> data(100);
} // automatically deallocated

Of course, for a small fixed-size array like this, you might as well just make it automatic:

void doSomething(){
    int data[100];
} // all automatic variables are deallocated
Community
  • 1
  • 1
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • shared_ptr and unique_ptr are also good choices if the allocated local variable is some more complicated types other than c-array, like a struct. – zealoct Jul 12 '19 at 09:26
5

The whole point of dynamic allocation like this is that you manually control the lifetime of the allocated object. It is needed and appropriate a lot less often than many people seem to think. In fact, I cannot think of a valid use of new[].

It is indeed a good idea to let the compiler handle the lifetime of objects. This is called RAII. In this particular case, you should use std::vector<int> data(100). Now the memory gets freed automatically as soon as data goes out of scope in any way.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
  • and so, how do you allocate memory in a function destined to be used outside ? – Guiroux Mar 03 '15 at 13:48
  • 3
    @Guiroux You return the vector by value. – Baum mit Augen Mar 03 '15 at 13:48
  • so you copy the whole vector ? – Guiroux Mar 03 '15 at 13:50
  • 3
    @Guiroux No, we have [RVO](https://en.wikipedia.org/wiki/Return_value_optimization) and move assignment. If you are pre C++11, an `std::vector&` input parameter *might* be the way to go, depending on the situation. – Baum mit Augen Mar 03 '15 at 13:52
  • so we are sure that this is actually optimized ? and why input parameter, juste use a return value of type `std::vector&` no ? EDIT : with the problem of having to use it only when a ref is actually created, ok my bad – Guiroux Mar 03 '15 at 13:57
  • 1
    @Guiroux No, then you are returning a reference to a local object which will go out of scope as soon as the function returns. So the returned reference will point to something which has already been deleted. – Lionel Mar 03 '15 at 14:02
  • 1
    @Guiroux Even if the compiler doesn't perform RVO (which I expect it to), since C++11 vector is movable so we can be sure it will be at most a move. – Chris Drew Mar 03 '15 at 14:02
  • @Guiroux: No, it can't return a reference. What would it refer to? Any local variables will have been destroyed before anyone can use the reference. – Mike Seymour Mar 03 '15 at 14:02
  • @Guiroux: You *can* be sure, by studying the output of your compiler. Or you can trust the compiler/library authors to have correctly implemented C++11 move semantics, and competently implemented RVO. You're trusting them anyway when you compile your code. – Benjamin Lindley Mar 03 '15 at 14:02
  • to whom say that you can't return by ref, well i forgot that the whole point of Baum was that he WASN'T dynamically allocating, and of course i was talking about dynamically allocated vector, which make no sense i admit :D EDIT : so what now ? why is dynamic allocation for ? – Guiroux Mar 03 '15 at 14:07
  • You can return a reference to a heap allocated object but that is dangerous in that it 'hides' the fact that ownership transferral has occurred. Programmers generally look at pointers and think 'hey possible lifetime management concerns here" which is often not thought of when references are involved. – Lionel Mar 03 '15 at 14:21
  • @Guiroux: Dynamic allocation is for exactly what you probably thought it was for before. Creating objects whose lifetimes outlast the scope in which they were created. But that allocation should be encapsulated in a thoroughly tested class like one of the standard library containers or smart pointers. If you have a need for a dynamic container which is not covered by one of the standard containers, or a composition of several of them, then maybe you have a use for manual dynamic allocation, but these situations are rare. – Benjamin Lindley Mar 03 '15 at 14:28
2

Actually you can access this variable outside of your doSomething() function, you just need to know address which this pointer holds.

In picture below, rectangle is one memory cell, on top of rectangle is memory cell address, inside of rectangle is memory cell value.

enter image description here

For example, in picture above, if you know that allocated array starts from address 0x200, then outside of your function you can do next:

int *data = (int *)0x200;
std::cout << data[0];

So compiler can't delete this memory for you, but please pay attention to compiler warning:

main.cpp: In function ‘void doSomething()’:
main.cpp:3:10: warning: unused variable ‘data’ [-Wunused-variable]
     int *data = new int[100];

When you do new, OS allocates memory in RAM for you, so you need to make OS know, when you don't need this memory anymore, doing delete, so it's only you, who knows when execute delete, not a compiler.

Sam Protsenko
  • 14,045
  • 4
  • 59
  • 75
  • In reality, it would be impossible or at least extremely ugly to expose the address like this, and you would let the address escape the allocating scope by returning a pointer or passing it to some other function that takes a copy of the pointer. Other than that, good point... the entire purpose of dynamic allocation is so that the user can dictate lifetime, not the scope. Many people probably misuse it with the latter intention, though. Suffice it to say I don't use dynamic allocation unless I have to, and currently working on a project with a 400 kB main object... I still never have to. – underscore_d Apr 09 '16 at 18:10
  • @underscore_d Of course, it was just an example to illustrate how things work. In real life one shouldn't do things like that. BTW, there is MISRA C standard (for mission critical systems) which prohibit dynamic memory allocations entirely. But in Linux kernel, for example, one shouldn't use stack extensively, because kernel stack is only about 4 KB. So all "big" variables and structures should be allocated dynamically. So it's all about context, I guess. – Sam Protsenko Apr 09 '16 at 18:25
  • True! And actually, I should've qualified my "In reality" to mean _on mainstream platforms_ - as on embedded systems, accessing addresses directly via a literal number and cast can be required, and IMO one of C/C++'s main strengths (combined with implementations that don't make it UB!) is enabling this. I guess usually this is either reading a hardware register or using _placement_ `new` into a well-defined address. – underscore_d Apr 09 '16 at 19:33
1

This is memory allocated on the heap, and is therefore available outside the function to anything which has its address. The compiler can't be expected to know what you intend to do with heap-allocated memory, and it will not deduce at compile time the need to free the memory by (for example) tracking whether anything has an active reference to the memory. There is also no automatic run-time garbage collection as in Java. In C++ the responsibility is on the programmer to free all memory allocated on the heap.

See also: Why doesn't C++ have a garbage collector?

Community
  • 1
  • 1
0

Since I can not access this variable outside the function, why doesn't the compiler call delete by itself every time a call to this function ends?

Because you should not allocate memory on the heap that you wouldn't use anyway in the first place. That's how C++ works.

EDIT: also if compiler would delete the pointer after function returns then there would be way of returning a pointer from function.

codekiddy
  • 5,897
  • 9
  • 50
  • 80
0

Here you have an int array dynamically allocated on the heap with a pointer data pointing to the first element of your array.

Since you explicitly allocated your array on the heap with new, this one will not be deleted from the memory when you go out of scope. When you go out of scope, your pointer will be deleted, and then you will not have access to the array -> Memory leak

Jérôme
  • 8,016
  • 4
  • 29
  • 35