High-level languages like C++, C#, and Java provide more advanced mechanisms for creating applications. The advantage is the ability of a developer to quickly create more complex systems. There can be tradeoffs for the language design choices. For example, C# and Java used garbage collection to prevent errors, such as dangling points, by taking away the job of determining when to release memory allocated from the heap. While C++ does not require garbage collection, its use of the heap can be hidden by objects defined by programmers.
The added complexity of C++ and the issues of hiding memory management are reasons why some developers shy away from C++. Many continue to use C, with its propensity for allowing developers to shoot themselves in the proverbial foot.
It is possible to use a subset of C++ so that it maintains the static nature of C, while retaining many of the more important features of C—including a much better type system, classes, and templates.
So what is a developer to do?
Bjarne Stroustrup and Herb Sutter have delivered an initial set of guidelines, known as Lifetimes I and II. The guidelines are just the first step of an open source project for C++ Core Guidelines. They are looking for help if you have a notion to lend a hand. The guidelines are at a 0.6 version level. The initial set is designed to free developers from leaks and dangling pointers. This includes raw pointers and references, but also all generalized Pointers such as iterators. One key aspect is that the guidelines should be readily adoptable by developers.
Here is an excerpt from Lifetimes I and II:
- We cannot tolerate leaks (failure to free) or dangling (use-after-free). For example, a safe std:: library must prevent dangling uses such as auto& bad = vec; vec.push_back(); bad = 42;.
- We need the raw efficiency of “just an address” pointers and references especially when used locally on the stack as function arguments/parameters, return values, and local variables. For example, a safe std:: library cannot just ban returning a reference from vector<T>::operator; it must still allow vec = 42; to return and write through a raw reference. We also need the flexibility of being able to write efficient user-defined iterators, ranges, views, and other indirections, as pure libraries with comparable abstraction overheads to today’s STL when used locally on the stack.
- We cannot tolerate run-time overheads, such as widespread reliance on tracing garbage collection or other run-time instrumentation, as required in languages like Java, C#, D, Go and others where GC is mandatory or required to use the full standard library. That would defeat the purpose of passing “just an address” because the total cost to the program would include the cost of tracing collection. It also takes us out of the realm of C++, where “zero overhead” and “don’t pay for what you don’t use” are table stakes.
- We cannot tolerate significant source code impact, such as heavy annotation as required in systems like Cyclone and Rust (see Related work). That would defeat both usability/comprehensibility and adoptability.
- We cannot tolerate excessive false positives, or flagging as lifetime “errors” code that is not actually leaking or dangling. Our goal is that the false positive rate should be kept at under 10% on average over a large body of code; that is, 90% of diagnosed errors should be actual or latent errors.
The paper is 45 pages long and goes into details about what to do and not do, as well as the how and why associated with the recommendations. Most are details that many C++ developers already know and follow. There are applications that already fit within these recommendations, and they have often been designed with these goals in mind. It just has not been formalized.
The challenge will be how these ideas can be implemented. The ideal situation would be a standard subset of C++ that completely controlled by the compiler and linker, so that developers could not accidentally deviate from the recommendations. This would be akin to the MISRA C/C++. Part of the challenge is that standard libraries need to be part of the mix. Likewise, development of third party libraries needs to be possible in a controlled fashion.
The idea is to create safe, bug-free code. The recommendations are based on the use of C++ std::unique_ptr and std:shared_ptr. The paper tries to efficiently enforce leak-free and dangle-free applications with little or no annotation. Some changes may require a slight reorganization of an existing application.
Tools that will validate the framework should be available soon. This should make it easier to write applications that are statically type-safe and without resource leaks. There are two other projects that are related. The Guideline Support Library (GSL) is a set of common types like array_view. The second is the Checker Tool that does application code validation.