Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Debunking C++ Myths
Debunking C++ Myths

Debunking C++ Myths: Embark on an insightful journey to uncover the truths behind popular C++ myths and misconceptions

Arrow left icon
Profile Icon Alexandru Bolboacă Profile Icon Ferenc-Lajos Deák
Arrow right icon
$9.99 $31.99
eBook Dec 2024 226 pages 1st Edition
eBook
$9.99 $31.99
Paperback
$39.99
Subscription
Free Trial
Renews at $19.99p/m
Arrow left icon
Profile Icon Alexandru Bolboacă Profile Icon Ferenc-Lajos Deák
Arrow right icon
$9.99 $31.99
eBook Dec 2024 226 pages 1st Edition
eBook
$9.99 $31.99
Paperback
$39.99
Subscription
Free Trial
Renews at $19.99p/m
eBook
$9.99 $31.99
Paperback
$39.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Table of content icon View table of contents Preview book icon Preview Book

Debunking C++ Myths

C++ Is Very Difficult to Learn

If you want to channel all its power

A prevalent belief between both C++ programmers and those who only hear about the language is that it’s very difficult to learn it. But what is this based upon? We will see that part of this belief is historical; not only has C++ been around for almost 30 years, but the initial standard was both unforgiving to programmers and required a lot of knowledge of memory management. Modern C++, after consequent improvements brought by the new standards C++11, C++ 14, C++ 17, C++ 20, and C++ 23, allows programmers to write code that is very similar to Java or C#. However, C++ has its specific niche in systems programming, which makes it necessary for programmers to learn more topics than necessary for other modern languages.

In this chapter, we’re going to cover the following main topics:

  • Why is C++ perceived as difficult to learn?
  • The hard parts of C++ and how to grasp them
  • The Stroustrup method for learning C++
  • The test-driven method for learning C++
  • With great power…

Technical requirements

The code examples in this chapter can be found in the GitHub repository https://github.com/PacktPublishing/Debunking-CPP-Myths in the ch1 folder. The code uses doctest (https://github.com/doctest/doctest) as a testing library, g++ and make for compilation, and targets C++ 20. You will also need valgrind (https://valgrind.org/) to check for memory leaks.

Why is C++ perceived as difficult to learn?

The beginnings of C++ saw it as an extension to C, only using the new paradigm, object-oriented programming (OOP), thus promising to solve the many problems of growing code bases. This initial version of C++ is unforgiving; you, the programmer, had to deeply understand how memory allocation and release works and how pointer arithmetic works, as well as guard against a myriad of subtleties that you’d be likely to miss and that usually ended up in an unhelpful error message. It didn’t help that the prevalent cultural zeitgeist of programmers back then was that a real programmer had to know all the intricacies of CPUs, RAM, various assembly languages, OS workings, and compilers. It also didn’t help that the standardization committee did almost nothing to reduce the possibility of such errors for decades. No wonder the fame of the language is following it almost 40 years later. My experience learning it only helps to understand the struggles to learn the language back then.

I had my first touches with C++ during my polytechnics studies, in the 90s. They had left me both intrigued and puzzled. I understood the power of the language, while it was actively fighting against me – or that’s how I perceived it. I had to struggle to write code that worked. I was not yet familiar with STL, which was yet to gain notoriety as part of the standard, so most of my first C++ programs dealt with pointer usage. A common question at C++ exams was about differentiating between an array of pointers and a pointer to an array. I can only imagine how helpful the complexities of the language were for building exam questions!

For the record, see here the difference between pointer to array and array of pointers, a common exam question for C++:

int(*pointerToArrayOf10Numbers)[10];

int *arrayOfTenPointers[10]

I continued learning C++ through practice and from books I could find before the internet would make the knowledge available to everyone. But the biggest jump in my understanding of the language was a project I worked on around the 2000s. The project lead, a very technical Belgian man, set for us very clear guidelines and a process we had to follow to get the best C++ code possible. This need for excellence did not come simply from his desires but from the project needs: we were building a NoSQL database engine many years before they would be given this label.

For this project, I had to study and know all the rules from the two seminal books on C++: Effective C++ and More Effective C++ by Scott Meyers. The two books document in total 90 guidelines for C++ programmers, ranging from issues of resource initialization and release to minute ways to improve performance, inheritance, exception handling, and so on. This is also when I started using STL extensively, although the standard library was much more limited in scope than it is today.

This newly acquired knowledge made my C++ programs more reliable and made me more productive. An important contributing factor was the process we used in synergy with the wisdom of the two books. We wrote unit tests, we performed design and code reviews, and we carefully crafted our code knowing that it would be dissected by a colleague before getting accepted in the code base. This made our code quasi-bug-free and helped us implement complex features with high performance in a reasonable time.

However, the language was still fighting against us. We knew how to write good C++ code, only it required a level of attention and care that inevitably slowed us down. Mastering C++ was not enough; the language had to give something back.

After this project, I left the C++ world and learned C# and managed C++, Java, PHP, Python, Haskell, JavaScript, and Groovy, to limit myself to those languages I’d used for professional programming. While every programming language offered higher abstractions and fewer headaches compared to C++, I still had nostalgia for my formative years in programming. The fact that I knew C++ and all the intricacies of memory management gave me a deep understanding of the inner workings of these other languages, allowing me to use them to their fullest. Haskell proved to be very familiar to me since it was closely mapping the meta-programming techniques I’d learned from the seminal book by Andrei Alexandrescu, Modern C++ Design. C++ was living on in my mind, not only as the first programming language I used professionally but also as a foundation for every other language I’ve used since.

To my delight, around 2010, the news came that the C++ standardization committee was finally making bold and frequent changes to the language. The last C++ standard had been for many years C++ 98; suddenly we were seeing a new version every three years. This rolling release of new versions of the standard allowed the introduction of the functional programming paradigm, of ranges, of new primitives for parallel and asynchronous programming, of move semantics. But the biggest change for anyone who wants to learn C++ today is the simplification of memory management and the introduction of auto types. The big breakthrough offered by these changes is that a Java or C# programmer can understand modern C++ programs, something we weren’t sure about back when Java and C# started.

This means the language is much easier to learn today than in the 90s. A good example of this change is the complete irrelevance of the old exam question on the difference between an array to pointers or a pointer to arrays; naked arrays can easily be replaced with a vector<> or a list<>, while pointers are replaced with the more precise shared_pointer<> or unique_pointer<>. This in turn reduces concerns related to allocation and release of memory for the pointers, thus both cleaning up the code and reducing the potential for the inscrutable error messages so prevalent in C++ 98.

We can’t say, however, that the C++ language is as easy to learn as the other mainstream ones today. Let’s see why.

The hard parts of C++ and how to grasp them

Is C++ as easy to learn as Java, C#, PHP, JavaScript, or Python? Despite all the language improvements, the answer is: most likely not. The important question is: Should C++ be as easy to learn as all these other languages?

The demise of C++ has been predicted for a very long time. Java, then C#, and nowadays Rust were in turn touted as complete replacements for our venerable subject of debate. Instead, each of them seems to carve their own niche while C++ is still leading in programs that require careful optimization or work in constrained environments. It helps that millions of lines of C++ exist today, some of them decades old. While some of them can be turned into cloud-native, serverless, or microservices architectures, there will always be problems better fit for the engineering style serviced by C++.

We conclude, therefore, that C++ has its own purpose in the world of development, and any new programming language faces a steep uphill battle to displace it. This observation comes with its consequence: specific parts of C++ will necessarily be more difficult to grasp than other languages. While Java or C# will spare you from thinking of memory allocation and what happens with the memory when you pass arguments to another method, C++ needs to take these issues head-on and give you the option to optimize your code as your context dictates.

Therefore, if you want to understand C++, you can’t escape memory management. Fortunately, it’s much less of an issue than it used to be.

Let’s analyze the differences by looking at how different languages manage memory allocation and release. Java uses a full object-oriented (OO) approach, in which every value is an object. C# designers decided to use both value types that include the typical numeric values, chars, structs, and enums, and reference types that correspond to the objects. In Python, every value is an object, and the type can be established later in the program. All these three languages feature a garbage collector that deals with memory release. The Python language uses a reference counting mechanism in addition to the garbage collector, thus allowing it to be optionally disabled.

The C++ 98 standard didn’t provide any built-in mechanism for pointer release, instead providing the full power and responsibility for memory management to the programmer. Unfortunately, this led to problems. Suppose that you initialize a pointer and allocate a large area of memory for a value. You then pass this pointer to other methods. Who is responsible for releasing the memory?

See, for example, the following simple code sample:

BigDataStructure* pData = new pData();
call1(pData);
call2(pData);
call3(pData);

Should the caller release the memory allocated in pData? Should call3 do it? What if call3 calls another function with the same pData instance? Who is responsible for releasing it? What happens if call2 fails?

The responsibility for memory release is ambiguous and, therefore, needs to be specified for every function or for every scope, to be more precise. The complexity of this problem increases with the complexity of programs and data flows. This would make most programmers using the other mainstream languages scratch their heads or completely ignore the responsibility and end up either with memory leaks or with calls to memory areas that have been already released.

Java, C#, and Python solve all these issues without asking the programmer to be careful. Two techniques are helpful: reference counting and garbage collection. Reference counting works as follows: upon every call to copy the value, the reference count is increased. When getting out of scope, the reference count is decreased. When the reference count gets to 0, release the memory. Garbage collectors work similarly, only they run periodically and check also for circular references, ensuring that even convoluted memory structures get released correctly, albeit with a delay.

Even back in the 2000s, nothing was stopping us from implementing reference counting in C++. The design pattern is known as smart pointers and allows us to think less about these issues.

In fact, C++ had from the very beginning yet another, more elegant way, to deal with this problem: pass-by-reference. There’s a good reason why pass-by-reference is the default way to pass objects around in Java, C#, and Python: it’s very natural and convenient. It allows you to create an object, allocate its memory, pass by reference, and the best part: its memory will automatically get released upon exiting the scope. Let’s look at a similar example to the one using pointers:

BigDataStructure data{};
call1(data);
call2(data);
call3(data);
...
void call1(BigDataStructure& data){
    ...
}

This time, it doesn’t really matter what happens in call1; the memory will be released correctly after exiting the scope in which data is initialized. The only limitation of reference types is that the memory allocated for the variable cannot be reallocated. Personally, I see this as a big advantage, given that modifying data can get messy very quickly; in fact, I prefer to pass every value with const& if possible. There are, however, limited applications for highly optimized polymorphic data structures that are enabled through memory reallocation.

Looking at the preceding program, if we ignore the & sign from call1 and rename the functions to fit their corresponding conventions, we could also read Java or C#. So, C++ could have been close to these languages from the beginning. Why isn’t it still similar enough?

Well, you can’t escape memory management in C++. The preceding code would not make a Java or C# programmer think of anything more; we established that C++ is different, though. The standardization committee realized that there are situations when we need to allocate memory in one function and release it in another and that it would be ideal to avoid using pointers to do that. Enter move semantics.

Note

Move semantics is a key feature introduced in C++11 to enhance performance by eliminating unnecessary copying of objects. It allows resources to be transferred from one object to another without creating a copy, which is especially beneficial for objects that manage dynamic memory, file handles, or other resources. To utilize move semantics, you need to implement a move constructor, which initializes a new object by transferring resources from a rvalue (temporary object) to the new object, and a move assignment operator, which transfers resources from a rvalue to an existing object for your class. The std::move function is a utility that casts an object to a rvalue reference, enabling move semantics. To help, the compiler creates the move constructor in certain conditions.

See in the following example how we might use move semantics to move the scope of a variable to the function process:

BigDataStructure data{};
process(data);
...
void process(BigDataStructure&& data){
}

Not much seems different, other than using two ampersand signs. The behavior is, however, very different. The scope of the data variable moves into the called function, and process, and the memory gets released upon exiting it.

Move semantics allows us to avoid copying big data values and to transfer the responsibility for releasing the memory into called functions. This is a unique mechanic between the languages we’ve discussed until now. To my best knowledge, the only other programming languages to implement these mechanics are the other contenders for systems programming: Rust and Swift.

This proves to us that, as much as C++ resembles Java or C# nowadays, it does require programmers to understand in more detail the way memory allocation and release work. We may have gotten over the exam questions that focused on minor syntax differences with big effects, but we haven’t gotten over the need to learn more than for the other languages.

Memory management, while a big part of the conversation, is not the only thing that makes things more difficult when learning C++. A few things are different and can be a bit annoying for newcomers:

  • The need for #ifndef preprocessor directives or the non-standard but often supported #pragma once to ensure that files are only included once
  • Separate .h files along with arbitrary rules of what goes in .h and what goes in .cpp
  • The very weird way to define interfaces with virtual methodName()=0

While we can ensure we use all these contraptions with rules and guidelines automatically applied by modern IDEs, their presence begs the question: Why are they still needed?

Barring the aforementioned, it is much more difficult to get over the fact that there’s no easy way to build a program and add external references. Java, with all its faults, has a single compiler, and Maven/Gradle as standard tools for dependency management that allow the download and integration of a new library with a simple command. C#, although fraught with the same issue for a long time, has pretty much standardized the community-created NuGet command for getting external libraries. Python features the standard pip command for managing packages.

With C++, you need to work more. Unlike Java and C#, which count on a virtual machine, your C++ programs need to be compiled for every supported target, and each target matched with the right libraries. Of course, there are tools for that. The two package managers I’ve heard mentioned the most are Conan and vcpkg. For build systems, CMake seems quite popular. The trouble is that none of these tools are standard. While it’s true that neither Java’s Maven/Gradle nor C#’s NuGet have started as a standard, their integration in tools and fast adoption means that they are the de facto standard today. C++ has a little bit more to go until this part of the language matures. We’ll talk more about these issues in a separate chapter, but it’s obvious that part of the C++ confusion is also generated by this complexity in trying out simple programs.

We looked at various complications in C++ compared to other languages, and we saw that while the language has gotten easier, it’s still not as easy as Java or C#. But the core question is: Is C++ very difficult to learn? To examine this, let’s look at three methods beginners can use to learn C++.

The Stroustrup method for learning C++

While the C++ standard has evolved toward simplicity, many of the learning materials have stayed the same. I can imagine it’s difficult to keep up with the C++ standard, given its newfound speed of change after 2010, and a question always remains: How much code is using the latest standard? Won’t students need to learn anyway the old ways of C++ so that they can deal with decades-old code bases?

Despite this possibility, we must progress at some point, and Bjarne Stroustrup thought the same. The third edition of his book, Programming: Principles and Practice using C++ (https://www.amazon.com/Programming-Principles-Practice-Using-C-ebook/dp/B0CW1HXMH3/), published in 2024, is addressed to beginners in programming and takes them through the C++ language. The book is a very good introduction to C++, and it’s accompanied by examples and a slide deck useful for anyone who wants to teach or learn the language.

It’s interesting to note that Stroustrup does not shy away from the topic of pointers and memory management, instead discussing the minimum necessary and immediately showing the ways modern C++ avoids them.

Let’s take as an example the slides associated with Chapter 16 that focus on arrays. They start with an explanation of naked arrays, their connection with pointers, and how you can get in trouble when using pointers. Then, alternatives are introduced: vector, set, map, unordered_map, array, string, unique_ptr, shared_ptr, span, and not_null. The deck ends with an example of a palindrome implementation in multiple ways, comparing the differences in safety and brevity of the code. Therefore, the whole purpose of this chapter is to show the various issues with arrays and pointers and how STL structures help avoid these issues.

The resulting code closely resembles the Java or C# variants. However, Stroustrup points out that pointer arithmetic is still useful to implement data structures. In other words, use it sparingly and only when you really need heavy optimizations.

We conclude, therefore, that the language creator doesn’t shy away from pointers and memory management but is focused on removing a lot of the potential issues that come with it. This enables C++ programmers to care less about memory management than in the C++ 98 era, but still a little bit more than in Java or C#.

The question still stands: Could beginners learn C++ without thinking much about pointers? Another teaching method seems to prove this is possible – if we want to train library users instead of library creators.

The Kate Gregory method – don’t teach C

In a talk at CppCon 2015 (https://www.youtube.com/watch?v=YnWhqhNdYyk), Kate Gregory makes the point that C is not a prerequisite for learning C++ and that it’s actively harming the learning process to start by teaching printf, naked arrays, and char pointers on the first day of a beginner C++ course.

Instead, her proposal is to start with the objects available in STL. The string and vector classes are quite clear to beginners, and operator overloading is also a very natural way to use these objects. Beginners expect that "abcd" + "efg" will result in "abcdefg"; there’s no need to explain the intricacies of operator overloading so that they can write simple programs. Moreover, this approach completely avoids discussing destructors and memory cleanup.

She continues by arguing that teaching lambdas to beginners is also quite easy if you start with an example. Consider trying to find a value in a vector. A first approach would be using a for loop that you can skim over. The second method is using std::find. But what if we want to find an even value in a vector<int> instance? This introduces lambdas very naturally in the conversation, without a whole discussion on all the possible ways to write them.

With this method, she argues that beginners will be able to use existing libraries. They will have some gaps in their knowledge, and in the case of a course for programmers working on a specific code base, you might need to have a section that introduces them to reading specific idioms useful for their work. And if you want these programmers to become library creators, then you need a more advanced course that dives into the depths of memory management and optimizations possible with pointers.

My 15 years of experience training people in complex skills tell me that this teaching method is very good. A key thing in training is to understand your target audience and do your best to avoid the curse of knowledge – the fact that you don’t remember how it was not to know something you know very well today. This method caters to the beginner mind by providing fast wins and good progression and giving the learners the courage to write code. So, it’s definitely an improvement in the methods of learning C++.

However, this is not the only way to learn a language. It’s a structured way, yes, but exploration is an important part of learning. There’s a way to learn C++ through exploration that uses a method typically associated with Twitter clashes: Test Driven Development (TDD).

The test-driven method for learning C++

Learning from books or structured courses is only one method; the other one is through personal exploration. Imagine learning C++, but instead of having to look through a bunch of code examples first, write the code as you think it should work and learn incrementally the differences between your intuition and the actual language. In fact, people naturally combine these two methods even when going through a structured learning course.

One downside of learning through exploration is that it’s hard to understand your progress, and you might often end up in difficult spots. A method comes to the rescue: TDD.

TDD is a counter-intuitive, effective method for incremental design. Its simplest description is the following:

  • Step 1, also known as red: Write one test that fails and shows the next case that needs to be implemented
  • Step 2, also known as green: Write the simplest code to make the test pass (and keep all the other tests passing)
  • Step 3, also known as refactor: Refactor the production code and the test code to simplify.

This red-green-refactor cycle repeats in very small cycles (often 5-10 minutes) until all the behaviors associated with the current feature or user story have been implemented.

Addressing TDD misconceptions

Personally, I am a fan of TDD, and I’ve used it for more than 10 years with a lot of success. In fact, I used TDD to write the sample code for this book. However, I know that TDD has been received with mixed feelings by the industry. Part of it is a failure in imagination, a common question being: How can I write a test for a method that doesn’t exist? Well, pretty much the same way in which you write code that hasn’t existed before: you imagine it’s there and focus on the desired inputs and outputs. Other criticism comes from failing to understand what TDD really is and how it works. Examples of faux TDD failures often involve starting with edge cases and showing that things get complicated very quickly when you should start with happy-path cases. Claims of TDD slowing down development are credible, but the truth is that this method helps us be more thorough and calculated, thus avoiding issues that are usually caught much later in the process and fixed with much sweat and stress. Finally, TDD is not a method for designing high-performing algorithms, but it can help you find a first solution that you later optimize with the help of a test suite.

To understand how to learn a programming language with a modified TDD cycle, we need to clarify two things about TDD. First, TDD is counter-intuitive because it requires a prolonged focus on the problem domain, while most programming courses teach us how to deal with the solution domain. Second, TDD is a method for incremental design; that is, finding a code structure that solves a specific problem in a step-by-step manner instead of all at once. These two characteristics make TDD the best fit for learning a new programming language, with some support.

Imagine that instead of learning the whole thing about C++ before being able to run a program, you just learn how to write a test. That is easy enough because tests tend to use a small subset of the language. Moreover, running the tests gives you instant feedback: failure or red when something is not right and success or green when everything is working fine. Finally, this allows you to explore a problem once you have one or more tests and figure out how to write the code such that the compiler understands it – which is what you want when you learn a language. It might be a bit problematic to figure out the error messages, particularly in C++, but if you have a person (or maybe an AI in the future) to ask for help, you’ll learn a lot on your way and see the green bar whenever you’ve learned something new.

This method has been tested on a small scale, and it worked remarkably well. Here’s how a learning session might work for C++.

Setup

At least two actors are involved in the learning process; we’ll call them the coach and the student. I prefer using a coach instead of the instructor because the goal is to guide the students on their own learning path rather than teach them things directly.

I will discuss the rest of the session as if only a student is involved. A similar setup can work with multiple students as well.

The first thing the actors need to do is to set a goal. Typically, the goal is to learn a minimum of C++, but it can also be learning more about a specific topic – for example, std::vector or STL algorithms.

In terms of the technical setup, this process works best with the two people watching the code on the same monitor and working side by side. While this is best done in person, remote is possible as well through various tools.

To start, the coach needs to set up a simple project composed of a test library, a production code file, and a test file. A simple way to run the tests needs to be provided, either as a button click, a keyboard shortcut, or a simple command. The setup I recommend for C++ is to use doctest (https://github.com/doctest/doctest), a header file-only test library that is very fast and supports a lot of the features needed for production.

Here’s the simplest structure for this project:

  • A test file, test.cpp
  • A production header file, prod.h
  • A doctest.h file
  • A Makefile allowing us to run the tests

A production cpp file may also be needed depending on the learning objectives.

The coach also needs to provide an example of a first test that fails and show how to run the tests. The student takes over the keyboard and runs the test as well. This test can be very simple, as in the following example:

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h" 
#include "prod.h"
TEST_CASE("Test Example"){
    auto anAnswer = answer();
    CHECK(anAnswer);
}

The production header shows the following:

bool answer(){
    return true;
}

The first order of business is then to make the test pass. The question the coach will keep asking the student is: “How do you think this will work? Write whatever you find intuitive.” If the student finds the correct answer, great! If not, show the correct answer and explain the reasons.

This example is very useful because it introduces a few elements of the language and shows them working: a function declaration, a variable, a test, and a return value. At the same time, the process is very nice because it gives the student a measure of progress: tests passing is good, and tests not passing means there’s something to learn.

With all these done, it’s time to enter the exploration phase.

Exploring the language

There are two ways to explore a programming language in this manner: through simple problems that introduce concepts one by one, also known as koans, or through solving a more complex problem.

Either way, the method stays the same: first, the coach writes a simple test or helps the student write a simple test that fails. Then, the student is asked to write the solution that seems most intuitive to them. Tests are run, and if they don’t pass, the coach needs to explain what is not working. Either the coach or the student makes the change, and when the tests pass, the step ends with clear progress.

During this process, it’s important to focus on the next natural step for the student. If the student has specific questions or curiosities, the next test can treat these instead of going through a scripted process. This adaptive way of learning helps students feel in charge, and the process gives them an illusion of autonomy that eventually turns into reality.

What about memory issues?

We spent some time in this chapter discussing the fact that C++ programmers need to learn more about memory management than their colleagues using other mainstream programming languages. How can they learn memory management with this method? Tests will not catch memory issues, will they?

Indeed, we want students to learn that they need to care about memory from the very beginning. Therefore, memory checks need to be integrated into our test suite. We have two options to do this: either use a specialized tool or select a test library that can detect memory issues.

A specialized tool such as valgrind is easy to integrate into our process. See the following example of a Makefile:

check-leaks: test 
    valgrind -q --leak-check=full ./out/tests
test: test.cpp
    ./out/tests
test.cpp: .FORCE
    mkdir -p out/
    g++ -std=c++20 -I"src/" "test.cpp"  -o out/tests
.FORCE:

The test.cpp target is compiling the tests. The test target depends on test.cpp and runs the tests. And the first target, check-leaks, runs valgrind automatically with options to show errors only when they come up so that students don’t get overwhelmed. When running make without any parameters, the first target is picked, so the memory analysis is done by default.

Assume we are running the tests with a memory leak, as in the following example:

bool answer(){
int* a = new int(4);
return true;
}

We are immediately greeted by this output:

==========================================================[doctest] test cases: 1 | 1 passed | 0 failed | 0 skipped
[doctest] assertions: 1 | 1 passed | 0 failed |
[doctest] Status: SUCCESS!
valgrind -q --leak-check=full ./out/tests
[doctest] doctest version is "2.4.11"
[doctest] run with "--help" for options
==========================================================[doctest] test cases: 1 | 1 passed | 0 failed | 0 skipped
[doctest] assertions: 1 | 1 passed | 0 failed |
[doctest] Status: SUCCESS!
==48400== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==48400==    at 0x4849013: operator new(unsigned long) ==48400==    by 0x124DC9: answer()

This output provides enough information for a conversation with the student.

The second option is to use a test library that already has memory leak detection implemented. CppUTest (http://cpputest.github.io/) is such a library, and it also has the advantage of supporting C and working for embedded code.

With these tools at our disposal, it’s now clear that this method works for teaching C++ to anyone who wants to try it or to dive deeper into specific parts, using exploration as a method.

Now that we learned two methods for learning C++ today, let’s go back to understanding what C++’s niche is and why it necessarily needs to be more complex than other languages.

With great power…

If there’s one thing I’d like you to take away from this chapter, it’s that C++ is a very powerful language, and with this power comes the programmer’s responsibility to use the appropriate level of abstraction.

I’m certain that a team of C++ programmers starting a new project today that solves specific business problems, using only the latest standard and specific libraries, can write code safely and with good performance without worrying about memory issues more than their Java or C# colleagues. In fact, it’s likely their code will resemble quite closely that written in other languages, with the expectation of better performance.

However, even such a team will occasionally face a choice: Do we implement a slightly less performant solution using the existing tools offered to us by STL, or do we optimize it to the stars by recursing to pointer arithmetic, move semantics, or custom memory management? This is when the power of C++ requires an equally high level of responsibility, care, and deep understanding.

Note

As I’m writing these words, the world is still in turmoil after the CrowdStrike incident of July 2024. The causes for the incident are still not 100% clear, despite the official disclosure (https://www.scmagazine.com/news/crowdstrike-discloses-new-technical-details-behind-outage). Either way, it looks as if a memory access error in a C++ program has led to a kernel panic in Windows systems around the world, grounding planes, stopping money transfers, and – most dreadfully – shutting down emergency services. Of course, this change should have never reached production, but it’s nonetheless a reminder of how much the world depends on software and of the consequences of the misuse of the power of C++.

Summary

In this chapter, we examined a statement: C++ is very difficult to learn. So, is it?

We looked at the history of C++ and how initially it was indeed a challenge to write even the simplest of programs. We saw how Java, C#, and Python deal with some of the problems programmers face with C++ and how the C++ standard has evolved unexpectedly fast in the past 15 years to remove its impediments.

While you can write C++ code that resembles Java or C# today, you will likely still need to understand memory management, a fact we exemplified using move semantics. We also saw that the methods for learning C++ have evolved with the language and with the times, with Stroustrup introducing pointers only in passing and quickly switching to higher-level structures available in STL. We saw that a modified TDD cycle can help people learn C++ in an exploratory manner and without getting overwhelmed by the complexity of error messages and the language.

We also pointed out that C++ has a disadvantage when it comes to tooling and portability. Installing a new dependency is a whole thing in C++, unlike Java, Python, or C#, which provide one de facto standard command to manage packages. This can turn off wannabe C++ programmers who make a deeper analysis.

Finally, despite the progress in the standard, we cannot forget the sheer size of C++ code that is in the world and not up to the latest standard. Chances are, even if you learn modern C++, your work will involve dealing with older code sooner or later.

We conclude, therefore, that C++ is still more difficult to learn than Java, C#, or Python, but that it’s closer than it’s ever been and that the power of the language continues to be attractive for a subset of programmers.

In the next chapter, Ferenc will examine the question: Is every C++ program standard? Or, maybe programmers are driven by solving problems and picking the solutions that work best in their environment, ignoring the standard or even creating idioms that end up in the standard after a while.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Trace the origins of C++ misconceptions and understand why they persist
  • Learn to avoid pitfalls caused by misunderstood C++ standards
  • Leverage the lesser-known features of the C++ programming language
  • Purchase of the print or Kindle book includes a free PDF eBook

Description

Think you know C++? Think again. For decades, C++ has been clouded by myths and misunderstandings—from its early design decisions to misconceptions that still linger today. Claims like "C++ is too hard to learn" or "C++ is obsolete" are often rooted in some truth, but they are outdated and fail to capture the language’s ongoing evolution and modern capabilities. Written by industry veterans with over 40 years of combined experience, this book uncovers the myths, exploring their origins and relevance in the context of today’s C++ landscape. It equips you with a deeper understanding of advanced features and best practices to elevate your projects. Each chapter tackles a specific misconception, shedding light on C++'s modern features, such as smart pointers, lambdas, and concurrency. You’ll learn practical strategies to navigate common challenges like code portability and compiler compatibility, as well as how to incorporate modern best practices into your C++ codebase to optimize performance and future-proof your projects. By the end of this book, you’ll have a comprehensive understanding of C++'s evolution, equipping you to make informed decisions and harness its powerful features to enhance your skills, coding practices, and projects.

Who is this book for?

This book is for intermediate-to-advanced C++ developers looking to deepen their understanding of the language’s complexities. It is perfect for coders eager to avoid common mistakes, hackers, scholars with a sense of humor, or anyone with an interest in C++. Programmers who want to expand their knowledge, refine existing skills, explore new paradigms, or dive into the nuances of C++, will find valuable insights. Technical leads and software engineering managers adopting new technologies or navigating the C++ ecosystem will also benefit from this book.

What you will learn

  • Comprehend the history of C++ and the design decisions that shape modern challenges
  • Master program flow and its underlying principles to resolve issues effectively
  • Tackle incompatibility across compilers and platforms with ease
  • Identify issues and avoid writing code that may lead to undefined behavior
  • Explore advanced C++ features not typically covered in academia
  • Address concerns about compiler code generation and optimizations
  • Understand why undefined behavior remains intentionally undefined

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Dec 30, 2024
Length: 226 pages
Edition : 1st
Language : English
ISBN-13 : 9781835884799
Category :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Product Details

Publication date : Dec 30, 2024
Length: 226 pages
Edition : 1st
Language : English
ISBN-13 : 9781835884799
Category :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
Banner background image

Table of Contents

14 Chapters
Chapter 1: C++ Is Very Difficult to Learn Chevron down icon Chevron up icon
Chapter 2: Every C++ Program Is Standard-Compliant Chevron down icon Chevron up icon
Chapter 3: There’s a Single C++, and It Is Object-Oriented Chevron down icon Chevron up icon
Chapter 4: The Main() Function is the Entry Point to Your Application Chevron down icon Chevron up icon
Chapter 5: In a C++ Class, Order Must There Be Chevron down icon Chevron up icon
Chapter 6: C++ Is Not Memory-Safe Chevron down icon Chevron up icon
Chapter 7: There’s No Simple Way to Do Parallelism and Concurrency in C++ Chevron down icon Chevron up icon
Chapter 8: The Fastest C++ Code is Inline Assembly Chevron down icon Chevron up icon
Chapter 9: C++ Is Beautiful Chevron down icon Chevron up icon
Chapter 10: There Are No Libraries For Modern Programming in C++ Chevron down icon Chevron up icon
Chapter 11: C++ Is Backward Compatible ...Even with C Chevron down icon Chevron up icon
Chapter 12: Rust Will Replace C++ Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.