Sign In Start Free Trial
Account

Add to playlist

Create a Playlist

Modal Close icon
You need to login to use this feature.
  • Book Overview & Buying Modern C++ Programming Cookbook
  • Table Of Contents Toc
  • Feedback & Rating feedback
Modern C++ Programming Cookbook

Modern C++ Programming Cookbook - Second Edition

By : Marius Bancila
4.7 (12)
close
close
Modern C++ Programming Cookbook

Modern C++ Programming Cookbook

4.7 (12)
By: Marius Bancila

Overview of this book

C++ has come a long way to be one of the most widely used general-purpose languages that is fast, efficient, and high-performance at its core. The updated second edition of Modern C++ Programming Cookbook addresses the latest features of C++20, such as modules, concepts, coroutines, and the many additions to the standard library, including ranges and text formatting. The book is organized in the form of practical recipes covering a wide range of problems faced by modern developers. The book also delves into the details of all the core concepts in modern C++ programming, such as functions and classes, iterators and algorithms, streams and the file system, threading and concurrency, smart pointers and move semantics, and many others. It goes into the performance aspects of programming in depth, teaching developers how to write fast and lean code with the help of best practices. Furthermore, the book explores useful patterns and delves into the implementation of many idioms, including pimpl, named parameter, and attorney-client, teaching techniques such as avoiding repetition with the factory pattern. There is also a chapter dedicated to unit testing, where you are introduced to three of the most widely used libraries for C++: Boost.Test, Google Test, and Catch2. By the end of the book, you will be able to effectively leverage the features and techniques of C++11/14/17/20 programming to enhance the performance, scalability, and efficiency of your applications.
Table of Contents (16 chapters)
close
close
13
Bibliography
14
Other Books You May Enjoy
15
Index

Using unnamed namespaces instead of static globals

The larger a program, the greater the chance that you could run into name collisions when your program is linked to multiple translation units. Functions or variables that are declared in a source file, intended to be local to the translation unit, may collide with other similar functions or variables declared in another translation unit.

That is because all the symbols that are not declared static have external linkage, and their names must be unique throughout the program. The typical C solution for this problem is to declare those symbols as static, changing their linkage from external to internal and, therefore, making them local to a translation unit. An alternative is to prefix the names with the name of the module or library they belong to. In this recipe, we will look at the C++ solution for this problem.

Getting ready

In this recipe, we will discuss concepts such as global functions and static functions, as well as variables, namespaces, and translation units. We expect that you have a basic understanding of these concepts. Apart from these, it is required that you understand the difference between internal and external linkage; this is key for this recipe.

How to do it...

When you are in a situation where you need to declare global symbols as static to avoid linkage problems, you should prefer to use unnamed namespaces:

  1. Declare a namespace without a name in your source file.
  2. Put the definition of the global function or variable in the unnamed namespace without making it static.

The following example shows two functions called print() in two different translation units; each of them is defined in an unnamed namespace:

// file1.cpp
namespace
{
  void print(std::string const & message)
  {
    std::cout << "[file1] " << message << '\n';
  }
}
void file1_run()
{
  print("run");
}
// file2.cpp
namespace
{
  void print(std::string const & message)
  {
    std::cout << "[file2] " << message << '\n';
  }
}
void file2_run()
{
  print("run");
}

How it works...

When a function is declared in a translation unit, it has an external linkage. This means two functions with the same name from two different translation units would generate a linkage error because it is not possible to have two symbols with the same name. The way this problem is solved in C, and sometimesin C++ also, is to declare the function or variable as static and change its linkage from external to internal. In this case, its name is no longer exported outside the translation unit, and the linkage problem is avoided.

The proper solution in C++ is to use unnamed namespaces. When you define a namespace like the ones shown previously, the compiler transforms it into the following:

// file1.cpp
namespace _unique_name_ {}
using namespace _unique_name_;
namespace _unique_name_
{
  void print(std::string message)
  {
    std::cout << "[file1] " << message << '\n';
  }
}
void file1_run()
{
  print("run");
}

First of all, it declares a namespace with a unique name (what the name is and how it generates that name is a compiler implementation detail and should not be a concern). At this point, the namespace is empty, and the purpose of this line is to basically establish the namespace. Second, a using directive brings everything from the _unique_name_ namespace into the current namespace. Third, the namespace, with the compiler-generated name, is defined as it was in the original source code (when it had no name).

By defining the translation unit local print() functions in an unnamed namespace, they have local visibility only, yet their external linkage no longer produces linkage errors, since they now have external unique names.

Unnamed namespaces also work in a perhaps more obscure situation involving templates. Prior to C++11, template non-type arguments could not be names with internal linkage, so using static variables was not possible. Conversely, symbols in an unnamed namespace have external linkage and could be used as template arguments. Although this linkage restriction for template non-type arguments was lifted in C++11, it is still present in the latest version of the VC++ compiler. This problem is shown in the following example:

template <int const& Size>
class test {};
static int Size1 = 10;
namespace
{
  int Size2 = 10;
}
test<Size1> t1;
test<Size2> t2;

In this snippet, the declaration of the t1 variable produces a compiler error because the non-type argument expression, Size1, has internal linkage. Conversely, the declaration of the t2 variable is correct because Size2 has an external linkage. (Note that compiling this snippet with Clang and GCC does not produce an error.)

See also

  • Using inline namespaces for symbol versioning, to learn how to version your source code using inline namespaces and conditional compilation
Visually different images
CONTINUE READING
83
Tech Concepts
36
Programming languages
73
Tech Tools
Icon Unlimited access to the largest independent learning library in tech of over 8,000 expert-authored tech books and videos.
Icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Icon 50+ new titles added per month and exclusive early access to books as they are being written.
Modern C++ Programming Cookbook
notes
bookmark Notes and Bookmarks search Search in title playlist Add to playlist download Download options font-size Font size

Change the font size

margin-width Margin width

Change margin width

day-mode Day/Sepia/Night Modes

Change background colour

Close icon Search
Country selected

Close icon Your notes and bookmarks

Confirmation

Modal Close icon
claim successful

Buy this book with your credits?

Modal Close icon
Are you sure you want to buy this book with one of your credits?
Close
YES, BUY

Submit Your Feedback

Modal Close icon
Modal Close icon
Modal Close icon