Blog 6 min read

The rise of the new language MC++

Share this article
The rise of the new language MC++

Over the last few years, we have been talking about the “C++ Renaissance.” We have to admit that Microsoft was a major part of this movement; I remember this video where Craig Symonds and Mohsen Agsen talked about it.

In 2011, Microsoft announced the comeback of C++ in many articles, and Microsoft C++ experts such as Herb Sutter gave numerous talks explaining why C++ was back, mostly recommending the use of Modern C++. At the same time, the C++11 standard was approved, and we began to talk about C++ as a new language.

By 2011, C++ had been in use for more than 30 years. It was not easy to convince developers that the new C++ actually simplified many frustrating facets of C++ usage, and that there was a new modern way to improve C++ code.

Let’s take memory management as an example—it is perhaps one of the most criticized aspects of C++. For many years, object allocation was done with the new keyword, and developers had to remember to invoke delete somewhere in the code. “Modern C++” resolved this issue by promoting the use of shared pointers.

When C++0x was announced a few years ago, I thought it would not have much impact on the C++ language, but I was wrong. Take a look at this code snippet from Folly — it looks like it was developed using a new language.

c0

The same observation applies to almost all of the Folly source code; its implementation looks very different from C++03 code.

How to limit the impact of the C++ past?

There’s no magic solution. We can hope that C++ compilers will help us by emitting warnings about deprecated practices, such as the old string manipulation functions (strcpy, strcat, …). But this solution will not have a big impact. Modern C++ is largely about learning and practicing new idioms.

Another solution would be to consider that a new language named “Modern C++” has been created. Let’s do the same web search as before, but this time for “Modern C++” object allocation — the first link will talk about smart pointers.

Discovering the new language MC++

A better way to discover the power of MC++ is to explore the source code of a mature project that uses its features. Folly from Facebook is a very good candidate.

Let's discover some MC++  features used in Folly:

1. auto

C++11 introduces type inference through the auto keyword, which means the compiler infers the type of a variable at the point of declaration. Folly uses auto for almost all its variable declarations; here’s an example from its source code.

c1

Using the auto keyword lets you spend less time writing out things the compiler already knows.

2. nullptr

The constant 0 has traditionally served the dual role of an integer constant and a null pointer constant. C++11 corrects this by introducing a new keyword to serve as a distinguished null pointer constant: nullptr.

In the Folly source code, all null pointers are represented by the new keyword nullptr; there’s no place where the constant 0 is used.

3. shared_ptr

Smart pointers are not a new concept; many libraries implemented them many years ago, the most popular one being boost::shared_ptr. What’s new is their standardization — there is no longer any need to use an external library to work with smart pointers.

Folly uses the standardized shared pointer extensively; only a few raw pointers remain in its source code.

4. Strongly-typed enums

“Traditional” enums in C++ export their enumerators into the surrounding scope, which can lead to name collisions if two different enums in the same scope define enumerators with the same name.

C++11 introduces the enum class keywords. They no longer export their enumerators into the surrounding scope. Moreover, we can now specify an underlying type for an enum.

c2

5. static assert

C++11 introduces a new way to test assertions at compile time, using the new keyword static_assert. This feature is very useful for adding conditions to template parameters, as shown in this template class from the Folly source code:

c3

6. Variadic template

A variadic template is a template that can take an arbitrary number of template arguments of any type. Both class and function templates can be variadic. Folly defines many variadic templates; here are two variadic template functions from the Folly source code:

c4

7. Range-based for loops

C++11 augmented the for statement to support the “foreach” paradigm of iterating over collections. It makes the code simpler and cleaner. Folly uses this feature extensively; here’s an example:

c6

8. Initializer lists

In C++03, initializer lists apply only to arrays; in C++11, they are no longer limited to arrays. The mechanism for accepting a {}-list is a function (often a constructor) accepting an argument of type std::initializer_list<T>. Here’s an example of a function accepting std::initializer_list as an argument.

c7

And here’s how it’s invoked.

c8

9. noexcept

If a function cannot throw an exception or if the program isn’t written to handle exceptions thrown by a function, that function can be declared noexcept.

Here’s an example from the Folly source code.

c9

10. move

C++11 introduced the concept of rvalue references (specified with &&) to differentiate a reference to an lvalue from a reference to an rvalue. An lvalue is an object that has a name, while an rvalue is an object that does not have a name (a temporary object). Move semantics allow modifying rvalues.

To support this, C++11 introduces two new special member functions: the move constructor and the move assignment operator.

c12c10

Here’s a good document that better explains the benefits of move semantics.

11. lambda

C++11 provides the ability to create anonymous functions, called lambda functions. You can refer to here for more details about this new feature.

Folly uses them in many functions; here’s an example from its source code:

c14

12. Explicitly defaulted and deleted special member functions

In C++03, the compiler provides, for classes that do not define them themselves, a default constructor, a copy constructor, a copy assignment operator (operator=), and a destructor. The programmer can override these defaults by defining custom versions.

However, there is very little control over the creation of these defaults. Making a class inherently non-copyable, for example, requires declaring a private copy constructor and copy assignment operator without defining them.

In C++11, certain special member functions can be explicitly disabled. For example, the following type is non-copyable, which makes the code simpler and cleaner.

c15

13. override identifier

In C++03, it is possible to accidentally create a new virtual function when one intended to override a base class function.

The override special identifier means that the compiler will check the base class(es) to see if there is a virtual function with this exact signature. If there is not, the compiler will report an error.

Folly uses this new feature extensively:

c18

14. std::thread

A thread class (std::thread) is provided, which takes a function object — and an optional series of arguments to pass to it — to run in the new thread.

In C++11, working with threads is simpler; here’s the new standard way to define a new thread, taken from the Folly source code:

c20

15. Unordered containers

An unordered container is a kind of hash table. C++11 offers four standard ones:

  • unordered_map
  • unordered_set
  • unordered_multimap
  • unordered_multiset

Folly uses these new containers in many places.

c21

Conclusion:

A piece of advice for new C++ developers: think of C++ as having changed its name, and use “Modern C++” rather than simply C++ in your web searches. The results will be very different—searching for C++ alone will often lead you to older practices.

Share this article