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
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
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
$39.99
Paperback Dec 2024 226 pages 1st Edition
eBook
$27.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
$39.99
Paperback Dec 2024 226 pages 1st Edition
eBook
$27.99 $31.99
Paperback
$39.99
Subscription
Free Trial
Renews at $19.99p/m
eBook
$27.99 $31.99
Paperback
$39.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with Print?

Product feature icon Instant access to your digital copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Redeem a companion digital copy on all Print orders
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
Product feature icon AI Assistant (beta) to help accelerate your learning
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
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
Estimated delivery fee Deliver to Japan

Standard delivery 10 - 13 business days

$8.95

Premium delivery 3 - 6 business days

$34.95
(Includes tracking information)

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 : 9781835884782
Category :

What do you get with Print?

Product feature icon Instant access to your digital copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Redeem a companion digital copy on all Print orders
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
Product feature icon AI Assistant (beta) to help accelerate your learning
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Japan

Standard delivery 10 - 13 business days

$8.95

Premium delivery 3 - 6 business days

$34.95
(Includes tracking information)

Product Details

Publication date : Dec 30, 2024
Length: 226 pages
Edition : 1st
Language : English
ISBN-13 : 9781835884782
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

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

What is the digital copy I get with my Print order? Chevron down icon Chevron up icon

When you buy any Print edition of our Books, you can redeem (for free) the eBook edition of the Print Book you’ve purchased. This gives you instant access to your book when you make an order via PDF, EPUB or our online Reader experience.

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela