March 23, 2021

Thoughts of C++

C++

C++ is a compiled high level language which bring fast performance with the advantages of being high level.
For me C++ is like riding a bicycle without training wheels , only you are riding on a rope between 2 buildings which are on fire.
In this article I’ll try to explain what are the benefits and disadvantages of writing C++.

Incredible performance

C++ to Assembly::

C++ is compiled straight into assembly - this assembly is also optimized if the correct flags are set.
This makes C++ very fast compared to languages that are compiled to byte code like C#.

C# to MSIL to assembly:

C# is compiled first to MSIL [Intermediate Code], its bytecode.
Then a special process called JIT [Just in time] is compiling it into Assembly.
Of course C# and the CLR [Common language runtime] have their own optimizations processes, but so far C++ has shown incredible performance compared to it.

HTTP performance

HTTP frameworks are common - but what isn’t known is how many are there, and there are lots of them in different language bindings.
The top most best performance are C++ with Rust following it - which is a language built on top of C++.

Taken from techempower.

Ease of usage

The Standard Library of C++ has improved drastically between the standards of C++ 11 and C++ 20.
C++ 20 includes new models like Co-Routines, modules, ranges, concepts and more…
This makes C++ a very convenient language to use while benefitting from it’s fast execution.

However this tends to be very messy which brings me to my next negative points.

High learning curve

C++ isn’t straightforward.
Being middle ground between a low-level language like C and having high-level abstractions like C# makes it unique in the way it should be learned and taught.
For some time C#, Java and python surpassed C++ in the STL and abstracted features - making basic features like threading, networking and generic programming very hard to develop in C++.
The recent standards tried to tackle these issues by adding more high-level abstractions which made C++ programmer’s life easier.

However until we get there - to C++ 23 or even C++ 26 - Other high-level languages are favored in terms of fast learning curve and useability by new programmers.

Confusing compiler errors

Code like this:

1
2
3
4
5
6
7
8
9
class A
{
A(int a) { }
};

int main()
{
auto s = std::make_shared<A>();
}

Can produce weird compiling errors like these:

1
2
Severity	Code	Description	Project	File	Line	Suppression State
Error C2664 'A::A(A &&)': cannot convert argument 1 from '_Ty' to 'const A &' TestingCPP C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.24.28314\include\xmemory 204

It will throw an error from the allocation of a shared_ptr while the real error is in the missing argument for the ctor.
This makes some errors very hard to resolve by non-exprt C++ programmers and even C++ programmers with expertise will take time to fix those.
Therefore writing code can lead to unexpected long debugging sessions.

Few things help us to deal with it:

Messy templating

Templating - or generic code in C++ - is messy.
This is true especially for library authors trying to make use of generic code.

In C# generic parameters are saved in the metadata, the CLR knows how to generate specific code.
In C++ generic properties are calculated in compile-time, making it harder for the compiler to assume things.

1
2
3
4
5
template <class Ta, class Tb, class Tc>
Tc Perform(Ta a ,Tb b)
{
return a + b;
}

This code assumes there is an operator + between the two classes.
We could produce these generic methods by just specifying the parameters:

1
2
3
int result = Perform<int, int, int>(1, 2);
auto result2 = Perform<long, long, long>(1, 2);
auto result3 = Perform<double, double, double>(1, 2);

However it becomes very messy when dealing with cross classes or different parameters.
What if we want to return a string but using 2 ints:

1
std::string result = Perform((int)1, (int)2);

We’ll have to implement it by doing a specific implementation:

1
2
3
4
5
template <int Ta, int Tb, class Tc = std::string>
std::string Perform(int a, int b)
{
return std::to_string(a + b);
}

However… what if we want wstring instead?
That’s right, another template!

1
2
3
4
5
template <int Ta, int Tb, class Tc = std::wstring>
std::wstring Perform(int a, int b)
{
return std::to_wstring(a + b);
}

By introducing variances to generic functions we are forced to use specific implementations, once we are there we may run into trouble when trying to reuse any bit of code.

Legacy code, expertise and language reputation

C++ has bad reputation among programmers, especially for the amount of legacy code programmers have to deal with.
Legacy code usually was written before the year 2000 - which means a lot of code was written before the language was even standardized - at 1998.

This means basic features like threading, time, file operations, networking were written using C APIS and OS APIs, and from my experience - they are not an easy sight.

Do you recall that C++ tries to be a high-level language?
This causes any corporation of new code troublesome into existing code.

Another important point in terms of legacy code - sometimes it can’t be replaced or it would cost too much to be replaced.
So any new code that is written usually is written in different languages - C#, Java, Python, JS, etc…

Low details are a concern

The header added important pointers - the smart pointers.
However, memory allocations are still a concern because the language doesn’t protect the programmer of mistakes.
It’s much easier to create low level exceptions and memory failures.
Therefore the high learning curve - the first thing programmers should learn is how to use the C++ STL wisely.
Instead of using raw pointers and raw arrays, it’s better to use std::unique_ptr and std::array.

1
2
3
4
5
6
7
8
9
10
A* ptr = new A {};

// Better =>
auto ptr = std::make_shared<A>();

int arr[10];

// Better =>

std::array<int,10> arr;

Compiling, Linking and Building a CI

C++ has improved in the building infrastructure in the past years, packging systems are developed, CMake is used for years now, Visual studio has improved dramatically, JetBrains developed a C++ IDE as well.
However, I found that NPM builds and C# builds are much more easier to deal with.

In this area C++ has a long path to walk before it will cross paths with other build systems.
Not to mention, scripting languages like Python help produce build-less CIs.

So it makes programmers and dev-ops developers spend time on compilation alone rather than focusing on the business logic.
I think it’s a crucial point for C++ because it makes other languages very popular for not needing to mess with compilation.
Don’t get me wrong - they have their own issues to deal with, but they are smaller compared to C++.

Testing

Testing isn’t new to C++ and is widlely used now, thanks to popular testing frameworks like GTest.
However, it still isn’t taught properly as part of C++ programming courses.
Because of the high learning curve, C++ developers need to learn a lot before even adding testing to their set of tools.
Still it can’t be avoided - it’s so necessary that it lengthens the learning time.

So why learn C++?

Althought its high learning curve, the benefit from learning C++ is learning many important concepts about compilation, memory allocations, code optimizations, code smells and overall - how to write better code.

All of modern patterns can be used in C++, and in the future C++ will have its place as a great high-level language.

So why use C++ in real projects?

C++ has few important roles in the industry:

If the developers use the modern approach for developments, even C++ can be a great choice for startups and new products.

Thanks for reading!

על הפוסט

הפוסט נכתב על ידי Ilya, רישיון על ידי CC BY-NC-ND 4.0.

שתפו את הפוסט

Email Facebook Linkedin Print

קנו לי קפה

#Software#Cplusplus