Despite its age and complexity, C++ is still a vital performer in the IT world. Originally released in 1985, it has since undergone a series of improvements, extensions and refinements. But its core values remain those that drove its development in the first place: it offers efficient low-level access as well as high-level abstraction for larger projects.
Despite the expansion of hardware capabilities, lightweight, fast and efficient coding languages are still essential for many applications. C++ has therefore retained importance for professional programmers in areas like real-time and embedded systems. The language is widely used for systems programming and low-level hardware control. And its speed and efficiency mean that many working in image processing, graphics and games development prefer to use C++.
However, traditionally C++ has also been renowned as difficult to learn, with many pitfalls for the unwary. For those schooled in more contemporary languages like Python, which use highly readable syntax and intuitive structures, aspects like memory management, pointers and complex polymorphism can be daunting. Plus, features like the preprocessor and operator overloading can be a minefield for the unwary.
Despite its age, C++ is still an industry standard and has also seen many updates and improvements over the years, with better support for design and usability. For developers who may have burnt their fingers in the past, it’s always worth taking another look to see the power and increasing usability of more modern iterations of C++.
The evolution of C++
C++ was first released to the public in 1985. In the early years at least, it was effectively a superset of C. Indeed, its creator, Bjarne Stroustrup, first set out to produce “C with classes”, combining the performance and low-level capabilities of the C language with the abstractions needed for large-scale software design. This dual alignment means that C++ is a hybrid language that can be both “close to the machine” as well as “close to the problem to be solved”.
But the features that facilitate this flexibility mean that C++ is often complex, with many features that are challenging for the novice. Luckily, over the years, the language has become fully standardised, with its own ISO working group. Several updates to the standard have appeared over the years, bringing in additional library features like built-in networking and parallelism. The revised standards have also introduced performance improvements like special mathematical functions, as well as usability upgrades such as ranges and better support for design patterns.
The latest iteration is C++23, which is due to be finalised in 2023. It will bring faster compilation, module support, a stack trace library and many other refinements and syntactic improvements to make life easier for coders.
Design Patterns
Since the mid-90s, design patterns have increasingly been used by software developers to simplify and improve their algorithms and system design. More general than algorithms but not as overreaching as programming paradigms, design patterns are reusable solution structures for common problems. Typical examples are the singleton pattern, often used to specify a single instance of a class, or the factory pattern, used to isolate object-creation conditions from other methods or classes.
There are also behavioural patterns, such as the chain of responsibility pattern. It facilitates tidy class encapsulation by allowing individual objects to determine whether to process a request or pass it along. Another good example is the observer pattern, which will be familiar to anyone well-versed in front-end development with JavaScript. It notifies parts of the application of state changes elsewhere, like user input or network statuses.
The strength of design patterns is that they are code-agnostic, meaning that, in theory, they can be used with virtually any programming language. However, they are particularly well-suited to object-oriented languages, where principles like encapsulation and polymorphism are easily implemented.
Although C++ predates the emergence of design patterns, its object-oriented structures and flexibility mean it is well-suited to implementing them. Over the years, these have become standardised, and developers can now consult easily reproducible examples of common C++ patterns that programmers can simply drop into their code. The generality of design patterns means that programmers can write more generic code that offers better comprehensibility to their teammates or future maintainers. Using design patterns in C++, therefore, brings it into line with other modern languages and software design principles. This can also help to mitigate the learning curve for those new to the language.
New innovative features and capabilities
A long-standing complaint among new coders has been the level of complexity in C++. To a certain extent, this is inevitable. C++’s performance is driven by its closeness to the actual functioning of the underlying hardware. This can be a barrier for the uninitiated. Meanwhile, its suitability for large applications is driven by some challenging levels of abstraction.
These factors can make C++ a tricky language for newcomers to penetrate, with execution structures that are hard to trace and code that can be challenging to read. Yes, other languages may be easier to understand, but that almost always comes at a cost in performance and flexibility. However, C++ has not stood still and more modern standards of the language have brought greater clarity and usability, with some of the data structures and features that programmers are used to in newer languages like Java or Ruby.
A great example of this is C++23’s support for modules. Modules help coders organise their applications cleanly, unifying collections of functions and templates in a more logical and separable structure that can be reused cleanly. Older versions of C++ achieved similar results by separating library include declarations into header files. However, with modules, the .h/.cpp file separation is no longer used, leading to source code that is easier to navigate. It’s a big organisational change for C++. In fact, Bjarne Stroustrup has affirmed that modular organisation is the most significant improvement yet in code organisation for the language.
Another recent innovation for the language has been the implementation of the ranges algorithms. They are defined in the <algorithm> header, with infrastructure and core types in the <ranges> header. Among other facilities, these provide a selection of sorting, searching and other algorithms. For example, sorting for containers can now be written with:
std::ranges::sort(container);
The ranges sort algorithm makes it easy to sort by given sub-parts of the element without needing to define a lambda. And of course, any number of different sort algorithms can be specified for C++23 – for example, introsort as well as partial_sort, stable_sort and others, as required.
The ranges algorithms include other features for convenience and efficiency. For example, if you simply want to partition rather than perform a full sort on a container you can use ranges::partition to return a subrange. There’s also a useful collection of set-related functions in the library, including:
- ranges::merge
- ranges::includes
- ranges::set_difference
- ranges::set_intersection
- ranges::set_union
There are many more ranges of algorithms available, which you can easily find in the C++ reference library. And with C++23 on the horizon, the future promises even more of these handy utilities.
Ranged loops in C++
To finish up, it’s worth taking a look at the ranged for-loop, another of the improvements over the years in C++. This feature serves as a good example of the move towards more readable syntactic structures and indicates the direction that C++23 will be taking.
Historically, for-loops in C++ took the same basic form as their C predecessors:
for (int i=0, i<n; i++) { ... }
While perfectly serviceable, this implementation requires more definition of iterators and conditions and lacks the ease of reading that developers in languages like Python or Ruby have come to expect. With these concerns in mind, since C++11, coders have been able to use this alternative syntax:
for (rangeDeclaration : rangeExpression) { ... }
It is also possible to define the iterator as a reference variable so that changes are binding outside the loop. In some ways, this is a relatively minor change, but it demonstrates a glimpse of intuitive and readable syntax, with tighter integration to its existing objects that coders of more modern languages may prefer. As such, it is valuable to see the direction being taken by C++.
Conclusions: C++ is younger than ever
As we have seen, C++ is by no means an extinct language. Though some developers may prefer the ease of use and domain-specificity of newer languages, C++ remains widely used and is rarely rivalled in terms of performance and flexibility. But the standards committee behind C++’s innovations are also conscious of the need for the language to keep up with the demands of the time. That’s why C++ continues to evolve and retain an appeal for any programmer who is serious about their craft.
Discover more about C++ with Luxoft
If you’re excited about C++ and want to expand your career with a company that shares your passion, be sure to take a look at the exciting opportunities provided by Luxoft.