views:

448

answers:

8

Apologies for the vast scope of question. But what is the design factor in managing memory in C++? For example: why is there a memory leak when a program does not release a memory object before it exits? Isn't a good programming language design supposed to maintain a "foo-table" that takes care of this situation ? I know I am being a bit naive, but what is the design philosophy of memory management in C++ with respect to classes, structs, methods, interfaces, abstract classes?

Certainly one cannot humanely remember every spec of C++. What is the core driving design of memory management?

+26  A: 

What is the core driving design of memory management ?

In almost all cases, you should use automatic resource management. Basically:

  • Wherever it is practical to do so, prefer creating objects with automatic storage duration (that is, on the stack, or function-local)
  • Whenever you must use dynamic allocation, use Scope-Bound Resource Management (SBRM; more commonly called Resource Acquisition is Initialization or RAII).

Rarely do you have to write your own RAII container: the C++ standard library provides a whole set of containers (e.g., vector and map) and smart pointers like shared_ptr (from C++ TR1, C++0x, and Boost) work very well for most common situations.

Basically, in really good C++ code, you should never call delete yourself1 to clean up memory that you've allocated: memory management and resource cleanup should always be encapsulated in a container of some kind.

1. Obviously, the exception here is when you implement an RAII container yourself, since that container must be responsible for cleaning up whatever it owns.

James McNellis
@James: even when implementing a SBRM container myself, I usually prefer to base it on `unique_ptr` or `scoped_ptr`. Much easier. Also one should not forget the excellent Boost Pointer Container library, not as necessary with `unique_ptr`, but still providing extra capabilities: `clone` and syntactic sugar with operators.
Matthieu M.
+1 "you should never call delete yourself": This is so true but so often misunderstood. I often hear the accusation: C++ hasn't got a garbage collector. If one follows the guidelines you listed, a garbage collector is largely superfluous.
Dimitri C.
When using automatic storage duration using the Stack, is there any limit to the size of my data I can store. Could I add say a million objects of "Person" class to an object of class "Nation" ?? What constrains the size of the object space in the Stack to avoid buffer overflow ??
de costo
@de costo: Right; it would be impractical to place a large object on the stack. The definition of "large" varies and depends on the circumstances. Anything with 1,000,000 subobjects would definitely be "large." On a modern desktop system, you can rely on having somewhere around 1MB of space available on the stack (you would want to consult your OS or runtime's reference to find out how much you get by default and how to change that).
James McNellis
+2  A: 

why is there a memory leak when a program does not release a memory object before it exits ?

Well, the OS typically clean up your mess for you. However, what happens when your program is running for an arbitrary amount of time and you have leaked so much memory that you can't allocate anymore? You crash, and that's not good.

Isn't a good programming language design supposed to maintain a "foo-table" that takes care of this situation ?

No. Some programming languages have automated memory management, some do not. There are benefits and drawbacks to both models. Languages with manual memory management allow you to say when and where resources are allocated and released, i.e., it is very deterministic. A relative beginner will however inevitably write code that leaks while they are getting used to dealing with memory management.

Automated schemes are great for the programmer, but you don't get the same level of determinism. If I am writing a hardware driver, this may not be a good model for me. If I were writing a simple GUI, then I probably don't care about some objects persisting for a bit longer than they need to, so I will take an automated management scheme every time. That's not to say that GC'd languages are only for 'simple' tasks, some tasks just require a tighter control over your resources. Not all platforms have 4GB+ memory for you to play around in).

There are patterns that you can use to help you with memory management. The canonical example would be RAII (Resource Allocation is Initialization)

Ed Swangren
Yes Sir !! you are right. But why is such a situation allowed by a programming language. Is this design deliberate to make programmers powerful or paranoid about every memory allocation that is made ??
de costo
Added more info.
Ed Swangren
@de costo: No, it's more that there was a time when that "magical thing" called a garbage collector did not exist.
Billy ONeal
And that, yes. The point is, the lack of a GC/automated memory management does not make a langauge "bad", it just gives you a bigger gun. Sometimes you will shoot your foot off with that gun, but you can't take out a battleship with a pea-shooter either. Use the right tool for the job.
Ed Swangren
@Ed: I'm not sure I agree with the "leaks are inevitable" -- If you consistently use RAII type containers, there's no reason there should ever be a leak.
Billy ONeal
Yes, the seasoned programmer can avoid these problems. My answer is directed more toward the OP than all programmers in general.
Ed Swangren
Clarified that a bit.
Ed Swangren
@Billy: garbage collectors predate C++ by about *20 years*.
Laurence Gonsalves
@Luarence: Yes -- I didn't explain myself very well. My point was that computers do not naturally have garbage collectors; someone had to come along and design, test, and build them. Not to mention that there is an overhead associated with that.
Billy ONeal
+3  A: 

C and C++ take the position that you, the programmer, know when you are done with memory you have allocated. This avoids the need for the language runtime to know much of anything about what has been allocated, and the associated tasks (reference counting, garbage collection, etc.) needed to "clean up" when necessary.

At the crux is the idea that: if you allocate it, you must free it. (malloc/free, new/delete)

There are several methods of helping manage this so that you don't have to explicitly remember. RAII and the smart pointer implementations that provide containers that do it is extremely useful and powerful for managing memory based on object creation and destruction. They will save you hours of time.

Joe
+4  A: 

It's not entirely clear whether you're asking about the philosophy of what's built into C++, or how to use it in a way that prevents memory leaks.

The primary way to prevent memory leaks (and other resource leaks) is known as either RAII (Resource Acquisition Is Initialization) or SBRM (Scope Bound Resource Management). Either way, the basic idea is pretty simple: since objects with auto storage duration are automatically destroyed on exit from their scope, you allocate memory in the ctor of such an object, and free the memory in its dtor.

As far as C++ itself goes, it doesn't really have a philosophy. It provides mechanisms, but leaves it up to the programmer to decide which mechanism is appropriate for the situation at hand. That's often RAII. Sometimes it might be a garbage collector. Still other times, other times it might be various sorts of custom memory managers. Of course, sometimes it's a combination of two or all three of those, or something else entirely.

Edit: As to why C++ does things this way, it's fairly simple: almost any other choice will render the language unsuited to at least some kinds of problems -- including a number for which C++ was quite clearly intended to be suitable. One of the most obvious of these was being able to run on a "bare" machine with a minimum of support structure (e.g., no OS)

Jerry Coffin
+1 -- note that the allocation doesn't necessarily need to happen in the constructor; see `std::auto_ptr` for an example where it does not.
Billy ONeal
+1  A: 

Philosophy-wise, I think there are two things that lead to C++ not having a garbage collector (which seems to be what you're getting at):

  • Compatibility with C. C++ tries to be very compatible with C, for better or worse. C didn't have garbage collection, so C++ doesn't, at least not by default. I guess you could sum this up as "historical reasons".

  • The "you only pay for what you use" philosophy. C++ tries to avoid imposing any overhead above C unless you explicitly ask for it. So you only pay the price of exceptions if you actually throw one, etc. There's an argument that garbage collection would impose a cost whenever an object is allocated on the heap so it couldn't be the default behavior in C++.

    Note that there is actually quite a bit of debate about whether garbage collection is actually more or less efficient than manual memory management. The better garbage collectors generally want to be able to move stuff around though, and C++ has pointer arithmetic (again, inherited from C) that makes it very hard to make such a collector work with C++.

Here's Stroustrup's (not really direct) answer to "Why doesn't C++ have garbage collection?":

If you want automatic garbage collection, there are good commercial and public-domain garbage collectors for C++. For applications where garbage collection is suitable, C++ is an excellent garbage collected language with a performance that compares favorably with other garbage collected languages. See The C++ Programming Language (3rd Edition) for a discussion of automatic garbage collection in C++. See also, Hans-J. Boehm's site for C and C++ garbage collection.

Also, C++ supports programming techniques that allows memory management to be safe and implicit without a garbage collector.

C++0x offers a GC ABI.

Laurence Gonsalves
A: 

What is the core driving design of memory management?

The driving design (no pun intended) is a bit like that of stick-shift transmission cars, as opposed to automatic transmission cars. Like a stick-shift car, C++ gives you freedom and control over the machine, but it's not as easy to use as automatic ones that take care of many things for you.

The following could easily have been written about C++ versus Java:

People who drive stick shift cars know the difference and the advantages of having total control of your car engine; people who drive cars with automatic transmissions do not. (...) Race cars, for example, do not use automatic transmissions. (...) People who are used to shifting gears will focus more on their driving making it more efficient and safe.

http://www.eslbee.com/contrast_stick_shift_or_automatic.htm

I should add, though, that C++ does have some mechanism that handle the memory for you, like others have mentioned, e.g. RAII, smart pointers etc.

A: 

C++ has no design philosophy wrt memory. All it has are two functions for allocating memory (new malloc) and two functions for freeing memory ( delete free ) and a frew related functions. Even those can be replaced by the programmer.

This is because C++ aims to run on generic computers. Generic computers are a CPU, memory (RAM, varieties of ROM) and a bus/busses for peripherals. There is no built in memory management on generic computers.

Now most computers come with memory ( typically a ROM variant ) which contains a bios/monitor. There you might see some rudimentary form of memory management --probably not.

Some computers come with OSes which will have memory management, but even there it is often primitive, and it is easy for me to claim that most computers running a C++ program have no OS at all.

If you expect C++ to run on any computer, it cannot have a memory management philosophy.

HandyGandy
Well, `new` and `delete` are operators, not functions, C++ offers a lot more than these for managing memory (what about `std::string`?), and memory management isn't a feature of an OS, but of a language's run-time environment.
sbi
+1  A: 

Isn't a good programming language design supposed to maintain a "foo-table" that takes care of this situation ?

Is it? why? A good programming language is one that lets you solve problems, no more, no less. A garbage collector certainly lowers the barrier of entry, but it also takes control away from the programmer, which might be a problem in some cases. True, on a modern 2.5GHz quad-core computer, and with today's advanced and efficient garbage collectors, we can live with that. But C++ had to work with much more limited hardware, ranging from desktop computers with a whopping 16MB of RAM down to embedded platforms with 16KB, and everything in between. It has to be usable in realtime code, where you can not just pause the program for 0.5 seconds to run a garbage collection.

C++ isn't just designed to be the language used on desktop computers. It's meant to be usable everywhere, on memory-limited systems, in hard realtime scenarios, on large supercomputers and everywhere else.

C++'s guiding principle is "you don't pay for what you don't use". If you don't want a garbage collector, you shouldn't have to pay the (steep) price of one.

There are very powerful techniques to manage memory in C++ and avoid memory leaks, even without a garbage collector. If a garbage collector was the only way to avoid memory leaks, then there'd be a strong argument in favor of adding one to the language. But it isn't. You just have to learn how to properly manage memory yourself in C++.

jalf
Could you list the powerful techniques to manage memory in C++ to avoid memory leaks apart from the ones listed the posts above ???
de costo