39

People who are used to garbage collected languages are often scared of C++'s memory management. There are tools, like auto_ptr and shared_ptr which will handle many of the memory management tasks for you. Lots of C++ libraries predate those tools, and have their own way to handle the memory management tasks.

How much time do you spend on memory management tasks?

I suspect that it is highly dependent on the set of libraries you use, so please say which ones your answer applies to, and if they make it better or worse.

5
  • 1
    Not that much, really... Especially with C++0x, references and STL. You can even write code with no memory management at all.
    – Coder
    Oct 3, 2011 at 13:56
  • 9
    In general: Not that much if you are experienced. A lot if you are novice to C++ (-> usually hunting memory/resource leaks).
    – MaR
    Oct 3, 2011 at 14:34
  • 1
    I find the real question, these days, more being about chasing down stale references. And it's usually pretty evident each time, just annoying that it was not caught before :p Oct 3, 2011 at 18:04
  • I know this is old, but IMO memory management is an integral part of being a good programmer. Abstractions like the STL containers are nice, but ignorance of memory is against the very idea of computation itself. One might as well ask how one can eliminate algebraic manipulation, logic, and looping from the programmer's arsenal.
    – geometrian
    Apr 30, 2014 at 4:22
  • How about "how much time is used to debug memory management gone awry?" Per se, memory management is possible and not so hard in C++. Fact is: setting it up is a precise craft, and it's very prone to fuckups. When you fuck up, you might not even notice, and tracking back to old errors with erratic behaviours that piled up over the time, is the real time sink you should be scared of. That's why the modern non garbage collected languages, (I'm thinking of rust) moved a lot of responsibility for checking typical errors over to the compiler.
    – ZJR
    Dec 18, 2017 at 3:26

8 Answers 8

55

Modern C++ makes you not worry about memory management until you have to, that is until you need to organize your memory by hand, mostly for optimization purpose, or if the context forces you to do it (think big-constraints hardware). I've written whole games without manipulating raw memory, only worriing about using containers that are the right tool for the job, like in any language.

So it depends on the project but most of the time it's not memory management that you have to handle but only object life-time. That is solved using smart pointers, that is one of idiomatic C++ tool resulting from RAII.

Once you understand RAII, memory management will not be a problem.

Then when you'll need to access raw memory, you'll do it in very specific, localized and identifiable code, like in pool object implementations, not "everywhere".

Outside of this kind of code, you'll not need to manipulate memory, only objects lifetime.

The "hard" part is to understand RAII.

9
  • 10
    Absolutely true. In the last 5 years, I've only written "delete"s when working with legacy code.
    – drxzcl
    Oct 3, 2011 at 15:36
  • 3
    I work in a highly stack-size constrained embedded environment. As cool as RAII is, it does not work well if stack space is at a premium. So it's back to pointer micromanagement.
    – bastibe
    Oct 3, 2011 at 17:00
  • 1
    @nikie I use the libraries smart pointers in the code that manipulate their API, then I use standard or boost smart pointers in code specific to my application (if I'm the one who decide about that). If you can isolate library code in some modules that abstract how they are used in your application, then you avoid API pollution from dependencies.
    – Klaim
    Oct 3, 2011 at 18:27
  • 13
    @Paperflyer: RAII won't take up more stack space than delete manually, unless you have one shitty implementation.
    – DeadMG
    Oct 3, 2011 at 19:51
  • 3
    @Paperflyer: The smart pointer on the heap takes the same space; the difference is that the compiler inserts the resource deallocation code on all exits from a function. And since this is so widely used, this is typically well-optimized (e.g. folding multiple exits together in ways that you can't - you can't put code after a return)
    – MSalters
    Oct 4, 2011 at 10:04
33

Memory management is used to scare children, but it is only one kind of resource that a programmer has to look after. Think file handles, network connections, other resources that you obtain from the OS.

The languages that support garbage collection usually not only ignore the existence of these resources, but they also make it harder to handle these properly by not providing a destructor.

So, in short, I'd suggest not that much of a C++ developer's time is spent worrying about memory management. As klaim's answer indicates, once you get a handle on RAII, the rest is just reflex.

19
  • 3
    I especially love how HttpWebRequest.GetResponse leaks handles and starts crashing in GC languages. GC is cool, until it starts sucking because resources still leak. msdn.microsoft.com/en-us/library/… See "Caution".
    – Coder
    Oct 3, 2011 at 14:50
  • 7
    +1 for viewing memory as resource. Legacy code or not, how many times do we need to shout out loud: Memory management is a skill and not a curse.
    – aquaherd
    Oct 3, 2011 at 16:16
  • 4
    @Coder Not sure if I follow.. GC sucks because it's possible to abuse resources anyway..? I think C# does a good job providing deterministic resource releasing using IDisposable...
    – Max
    Oct 3, 2011 at 16:32
  • 8
    @Max: Because if it's garbage collected, then I expect not to worry about stupid resources via using and custom IDisposables. Resources left the scope, that's it, they should be cleaned. In reality, though, I still have to think and guess which ones will leak, and which ones won't. Beats any reason to use GC language in the first place.
    – Coder
    Oct 3, 2011 at 16:52
  • 5
    @deadalnix They do have the finalize construct. However, you don't know when it will be called. Will it be before you run out of sockets, or WebResponse objects? You'll find articles aplenty that tell you that you should not rely on finalize - with good reason.
    – Dysaster
    Oct 3, 2011 at 19:39
14

Pretty much none. Even old technologies like COM, you can write custom deleters for the Standard pointers that will convert them in a very short time. For example, std::unique_ptr can be converted to uniquely hold a COM reference with five lines of a custom deleter. Even if you have to manually write your own resource handler, the prevalence of knowledge like SRP and copy-and-swap makes it relatively easy to write a resource managing class to use forever more.

The reality is that shared, unique, and non ownership all ship with your C++11 compiler, and you just have to write small adapters to make them work even with old code.

4
  • 1
    How much skill with C++ do you have to have to a) write a custom deleteter b) know that a custom deleter is what you need? I ask because it seems easy to pick up a new GC'd language and get close-to-correct without know the whole thing -- it it easy to get right in C++ as well? Oct 3, 2011 at 19:46
  • 2
    @SeanMcMillan: Custom deleters are trivial to write and deploy, the COM one I mentioned is five lines for all COM types, and anyone with a basic training in modern C++ should be familiar with them. You can't pick up a GCed language, because surprise- the GC won't collect COM objects. Or file handles. Or memory obtained from other systems. Or database connections. RAII will do all of those things.
    – DeadMG
    Oct 4, 2011 at 8:31
  • 2
    By "Pick up a GC'd language," I meant that I've hopped between Java/C#/Ruby/Perl/Javascript/Python, and they all have the same resource management style -- memory is mostly automatic, and everything else, you have to manage. It sounds to me like you're saying C++'s management tools let you manage file handles/db connections/etc in the same way as memory, and that it's relatively straightforward once you learn it. Not brain surgery. Do I understand correctly? Oct 4, 2011 at 12:58
  • 3
    @SeanMcMillan: Yes, that's exactly right, and it's not complex.
    – DeadMG
    Oct 4, 2011 at 19:21
11

When I was a C++ programmer (a long time ago), I spent a long time worry about memory management bug when trying to fix hard to reproduce bugs.

With modem C++, memory management is a lot less of an issue, but can you trust everyone on a large team to get it right. What is the cost/time of:

  • Training (not many programers arive with a good understanding of the issues)
  • Code reviews to find memory management issues
  • Debugging of memory management issues
  • Always having to keep in mind that a bug in one part of the app, may be due to a memory management issue in a unrelated part of the app.

So it is not just the time spending “doing”, this is more of an issue on large projects.

5
  • 2
    I think some C++ projects have despaired of ever fixing some of their memory leaks due to badly written code. Bad code is going to happen, and when it does it can take up a lot of other people's time as well.
    – Jeremy
    Oct 3, 2011 at 19:29
  • @Jeremy, I found when I moved from C++ to C#, there was still as much badly written code (if not more), but at least it was a lot easy to find the part of the program that had a given bug.
    – Ian
    Oct 3, 2011 at 20:12
  • 1
    yes this is a lot of why most shops have moved to Java or .NET. Garbage collection mitigates the inevitable damage of bad code.
    – Jeremy
    Oct 3, 2011 at 20:35
  • 1
    Oddly enough, we don't have those problems. Oct 3, 2011 at 20:52
  • 1
    @DavidThornley, I think a lot of the problem were from writing UI code in C++, these days most C++ code I see is not UI
    – Ian
    Oct 4, 2011 at 8:33
2

I use boost and TR1 libraries a lot, and they make memory management in the strict sense (new/delete) a non-issue. On the other hand, memory allocation in C++ is not cheap, and one must pay attention to where these fancy shared pointers are created. You end up using workspaces a lot, or working with stack-based memory. In general, I'd say that it's mostly a design problem, not an implementation problem.

2

how much time does it take as a client? very little, once you get the hang of it. when a container manages lifetime and references, it's really very easy. imo, it's far simpler than manual reference counting, and it's practically transparent if you consider the container you use as documentation which the compiler conveniently prevents you from performing invalid ownership transfers in a well designed typesafe system.

most of the time i spend (as a client) is spent containing types from other apis, so they function well within the context of your programs. example: this is my ThirdPartyFont container, and it supports these features, and implements destruction this way, and reference counting this way, and copying this way, and.... Many of those constructs need to be in place, and it's often the logical place to put them. whether you want to include that as time or not depends on your definition (the implementation needs to exist when interfacing with these apis, anyway, right?).

after that, you will need to take memory and ownership into consideration. in a lower level system, that's good and necessary, but it can take some time and scaffolding to implement how you should move things around. i don't see it as a pain since this is a requirement of a lower level system. ownership, control, and responsibility are evident.

so we can turn that towards c based apis which use opaque types: our containers allow us to abstract all the little implementation details of managing the lifetime and copying of those opaque types, which ultimately makes resource management very very simple and saves time, defects, and reduces implementations.

it's really very simple to use these - the problem (coming from GC) is that you have to now consider your resources' lifetimes. if you get it wrong, it can take a lot of time to solve. learning and integrating explicit lifetime management is understandably complex in comparison (not for all people) -- that's the real hurdle. once you are comfortable controlling lifetimes and using good solutions, then it's really very easy to manage resource lifetimes. it's not a significant part of my day (unless a difficult bug has crept in).

if you're not using containers (auto/shared pointer), then you're just pleading for pain.

i've implemented my own libraries. it takes me time to implement those things, but most people reuse (which is usually a good idea).

1

You mean like manually having to free memory, close files, things of this sort? If so, I'd say the minimum and typically less than most other languages I've used, especially if we generalize that not just to "memory management" but "resource management." In that sense, I actually think C++ requires less manual resource management than, say Java or C#.

It's mainly due to destructors which automate destroying the resource (memory or otherwise). Typically the only time I have to free/destroy a resource manually in C++ is if I'm implementing a vlow-level data structure (something most people don't need to do) or using a C API where I just spend a little time wrapping the C resource that needs to be manually freed/destroyed/closed into a RAII-conforming C++ wrapper.

Of course if a user requests to close an image in an image editing software, I have to remove the image from a collection or something. But hopefully that doesn't count as "memory" or "resource" management of a kind that matters in this context, since that's pretty much required in any language if you want to free the memory associated with that image at that time. But again all you have to do is remove the image from the collection and the image destructor takes care of the rest.

Meanwhile if I compare to, say, Java or C#, you often find people having to close files manually there, manually disconnect sockets, set object references to null to allow them to be garbage collected, etc. There's a whole lot more manual memory and resource management in those languages if you ask me. In C++ you often don't even need to unlock a mutex manually, since the mutex locker will do that for you automatically when the mutex goes out of scope. For example, you should never have to do things like this in C++:

System.IO.StreamReader file = new System.IO.StreamReader(path);
try
{
    file.ReadBlock(buffer, index, buffer.Length);
}
catch (System.IO.IOException e)
{
    ...
}
finally
{
    if (file != null)
        file.Close();
}

There's no need to be doing things like closing files manually in C++. They end up closing themselves automatically the instant they go out of scope whether they go out of scope as a result or normal or exceptional execution paths. Similar thing for memory-related resources like std::vector. Such code like file.Close() above would often be frowned upon since, especially in the context of a finally block, that suggests the local resource needs to be freed manually when the whole mindset around C++ is to automate that.

In terms of manual memory management, I'd say C requires the maximum, Java/C# a medium amount, and C++ the minimum among these. There are many reasons to be a bit shy of using C++ since it's a very difficult language to master, but memory management shouldn't be one of them. To the contrary I actually think it's one of the easiest languages out there in this one aspect.

Of course C++ does let you start manually allocating memory and invoking operator delete/delete[] to manually free memory. It also lets you use C functions like malloc and free. But that's ancient-style coding practices of a kind which I think became obsolete long before people give credit, since Stroustrup was advocating RAII before he even coined the term from very early on. So I don't even think it's fair to say "modern C++" automates resource management, because that was supposed to be the purpose all along. You can't practically get exception-safety otherwise. It's just that a lot of misguided developers during the early 90s tried to use C++ as like C with objects, often completely ignoring exception-handling, and it was never supposed to be used that way. If you use C++ the way it was practically always intended to be used, then memory management is totally automated and generally not something you have to manually deal with (or should be dealing with) much at all.

1
  • 1
    Modern Java has "try with resources" which removes all that messy code in the finally block. It is seldom necessary to have a finally block. Looks like the designers have copied the RAII concept.
    – kiwiron
    Dec 18, 2017 at 19:45
0

Depends on the senior technical leads in the team. In some companies ( including mine ), there is no concept called smart poiner. It is considered fancy. So, people simply put deletes all over the place and there is a drive for memory leak fixing for every 2 months. New wave of delete statements arrive everywhere. So, depends on the company and the kind of people who work there.

2
  • 1
    Is there something in your environment that stops you from using auto_ptr and friends? Oct 7, 2011 at 12:30
  • 2
    sounds like your company doesn't write C++ code, you're writing C.
    – gbjbaanb
    Dec 23, 2013 at 23:08

Not the answer you're looking for? Browse other questions tagged or ask your own question.