21

Is it possible to either create a coding standard or use of a library that can be proved to eliminate any memory management errors in C++?

I'm thinking of something like Java, it is just impossible to for example have dangling pointers in Java applications.

Jesus H
  • 1,180
  • 3
  • 13
  • 25
  • 6
    ***What does it take to write memory safe C++ applications?*** The first step is is to avoid using `new`. – drescherjm Jan 12 '17 at 15:05
  • 3
    Using std containers and smart pointers (`especially unique_ptr<>`) is a huge step (or "coding standard" as you call it) in the right direction. – A.S.H Jan 12 '17 at 15:09
  • 1
    There is only one way that can avoid memory errors in C++: CONSTANT VIGILANCE! Never assume a pointer is valid unless you have proven it, never assume a fixed buffer will be big enough, always use smart pointers, etc. There is a ton of ways to shoot your own feet, including quite a few standard library functions which are inherently unsafe. The only defense is to know exactly what is going on at each point, and safeguard against all possible pitfalls. – cmaster - reinstate monica Jan 12 '17 at 15:16
  • To get the memory safety of Java, you would need to implement garbage collection. However, it is simply impossible to implement a C++ garbage collector that always works correctly: the possibility of pointer arithmetic prevents this. And you absolutely need pointer arithmetic to be able to access array/vector elements in C++. The second downside of memory safety is speed: It's the main reason why java will always remain significantly slower than C++. – cmaster - reinstate monica Jan 12 '17 at 15:34
  • 3
    C++ doesn't give you memory safety. Other languages do. You should either drop provable memory safety requirements or C++. – nwp Jan 12 '17 at 15:36
  • @nwp C++ gives you memory safety if you use it right. C++ also gives you speed equal to C, and abstractions as powerful as fluffy, slow languages like Python. – Erik Alapää Jan 12 '17 at 15:45
  • @cmaster: Languages are not fast or slow. Programs, run in particular environments with particular user input, are fast or slow. You can always construct a use case in which one language is faster than the other. – Christian Hackl Jan 12 '17 at 16:36
  • @ChristianHackl While you are right in the general case (some languages being more suited to implement some things faster than another, while the other is more suited to implement some other things faster than the first), this is not true when comparing to C/C++: Both provide basically direct access to the machine below. As such, there can be no problem that can be solved any faster in any other language than the best performing C/C++ solution. In this sense C/C++ is at least as fast as any other language. However, Java adds overhead in core functionality, and is thus really slower than C/C++. – cmaster - reinstate monica Jan 12 '17 at 16:58
  • @cmaster: Well, you could implement both C and C++ for a virtual machine, and you could build hardware to match Java's bytecode :) But that's not the point. I think what I was trying to say is that there are use cases where GC improves the general performance of a piece of software. Many negative opinions about Java's GC performance date back to the 1990s, but those things have evolved, and matured. – Christian Hackl Jan 12 '17 at 17:11
  • 1
    @ChristianHackl No-one stops you from implementing a garbage collector in C++ either, if your use-case requires it (been there, done that). It just won't be a general purpose, failsafe one like the one in Java due to the problems I outlined in my comment above. And while you certainly have a point saying that C implemented on a virtual machine would likely be suboptimal, I don't see any way that garbage collection could ever outperform correct manual memory management. Unless, of course, the C++ memory allocator is suboptimal (had that, prooved it, worked around it :-) ). – cmaster - reinstate monica Jan 12 '17 at 17:19

2 Answers2

13

Is it possible to either create a coding standard or use of a library that can be proved to eliminate any memory management errors in C++?

Yes and no.

Even if you use a very strict standard, doing so will limit you to a very narrow subset of the C++ language. For example, the Power of Ten (Rules for Developing Safety-Critical Code) says that you should disable heap usage entirely. However that alone doesn't stop you from creating memory corruption.

I think if there were an exact answer to this question, the industry would've solved this decades ago, but here we are...

I don't believe that there is a definite way to make sure your code is totally safe, but there are best practices which will help you make sure there are as few problems as possible.

Here are some suggestions:

  • As mentioned earlier, disallowing heap usage entirely might help you get rid of all the memory management problems, but it doesn't solve the problem completely because it doesn't save you from eg. stray pointer writes.
  • I recommend you read the about The Rule of Three, Five and Zero which explain some of the stuff you need to take care of.
  • Instead of managing memory on your own, use smart pointers like shared_ptr, unique_ptr etc. But course, you could still abuse these if you wanted to. (For example shared_ptr will not help you if you have circular references...)
  • Use memory checker tools like valgrind, which can help you discover problems and verify that your code is error-free.

Even if you keep to any coding standard or best practice, errors can and will happen. Nobody guarantees that you will be safe. However, by keeping to these suggestions you can minimize the chance and impact of errors.

Graham
  • 7,431
  • 18
  • 59
  • 84
Venemo
  • 18,515
  • 13
  • 84
  • 125
2

Is it possible to either create a coding standard or use of a library that can be proved to eliminate any memory management errors in C++?

No.

But the same is true for Java. While Java does not technically allow memory leaks, it does have them (and other resource leaks) in practice if you do not pay attention.

A classical example, known particularly well in the Android world, is when a collection of listener instances keeps growing the longer a program runs, because listeners forget to unregister themselves. This can quickly cause hundreds of MBs leaking in a GUI application when the listener is an instance of some window or view class that keeps itself references to big graphics. Since all of that memory is still reachable, garbage collection cannot clean it up.

The fact that you have not technically lost the pointer (it's still in the collection) does not help you at all. Quite the contrary; it's the cause of the leak because it prevents garbage collection.

In the same vein as above, while Java does not technically allow dangling pointers, similar bugs can cause you to access a pointer to some window or view object which is still in a valid memory area for your program but which should no longer exist and is no longer visible. While the pointer access itself does not cause any crash or problem, other kinds of errors or crashes (like a NullPointerException) usually follow soon enough because the program logic is messed up.


So much for the bad news.

The good news is that both languages allow you to reduce memory-management problems if you follow simple guidelines. As far as C++ is concerned, this means:

  • Use standard collections (like std::vector or std::set) whenever you can.
  • Make dynamic allocation your second choice. The first choice should always be to create a local object.
  • If you must use dynamic allocation, use std::unique_ptr.
  • If all else fails, consider std::shared_ptr.
  • Use a bare new only if you implement some low-level container class because the existing standard container classes (likestd::vector or std::set) do not work for your use case. This should be an extremely rare case, though.

There is also the Boehm garbage collector for C++, but I've never used it personally.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62
  • 4
    Running out of memory is bad, but it is not a memory safety violation. Given the same input data, failure to free memory in a memory safe language will cause reproducible behaviour, memory exhaustion. Memory corruption is not necessarily reproducible, it might not even crash 99% of runs. Memory safety violation is a far worse category of bug than memory exhaustion. Any responsible programmer should be very keen to work only with languages that enforce a memory safe subset. Smart pointers in C++ are an improvement, but they do still suffer from memory safety violations. – Nick Treleaven Mar 01 '21 at 17:11