top of page

Craft, activity and play ideas

Public·7 members

Exceptional C++: A Book by Herb Sutter with 58 Tips and Tricks for C++ Programmers



Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions by Herb Sutter




If you are a C++ programmer who wants to improve your skills, learn from the experts, and solve challenging problems, then this book is for you. Exceptional C++ is a collection of 47 articles that cover various aspects of C++ programming, such as generic programming, exception safety, class design, inheritance, templates, and more. Each article presents a problem or a puzzle, followed by a detailed analysis and solution. The book is written by Herb Sutter, one of the most influential C++ experts in the world. In this article, I will give you an overview of the book, its author, and its main topics.




exceptional c herb sutter pdf 58



Introduction




What is Exceptional C++?




Exceptional C++ is not a typical C++ book that teaches you the syntax and features of the language. Rather, it is a book that challenges you to think deeply about how to use C++ effectively and correctly. The book assumes that you already have some experience with C++, but it does not require you to be an expert. The book covers topics that are relevant for both beginners and advanced programmers, such as:


  • How to write generic code using templates and the standard library



  • How to handle errors and exceptions in a robust and safe way



  • How to design classes and interfaces that are easy to use and extend



  • How to avoid common pitfalls and traps that can lead to bugs and inefficiencies



  • How to apply best practices and idioms that are widely accepted by the C++ community



The book is divided into three parts, each containing several articles that focus on a specific theme. Each article consists of four sections:


  • A problem statement that poses a question or a puzzle about some aspect of C++ programming



  • A hint section that gives you some clues or suggestions on how to approach the problem



  • A solution section that explains the correct answer and the reasoning behind it



  • A discussion section that explores alternative solutions, trade-offs, implications, and extensions of the problem



The book is designed to be read in any order, depending on your interests and needs. You can read each article independently, or you can follow the suggested reading order that groups related articles together. You can also use the book as a reference or a source of inspiration for your own projects.


Who is Herb Sutter?




Herb Sutter is one of the most respected and influential C++ experts in the world. He is the author of several books, including C++ Coding Standards, More Exceptional C++, and C++ Concurrency in Action. He is also a prolific writer of articles, columns, and blogs on various C++ topics. He is the chair of the ISO C++ standards committee, where he has been involved in the design and evolution of the language since 1997. He is also a software architect at Microsoft, where he leads the C++ team. He has been awarded the Dr. Dobb's Excellence in Programming Award and the Software Development Magazine Jolt Award for his contributions to the C++ community.


Why read this book?




This book is a valuable resource for any C++ programmer who wants to learn from the best and improve their skills. By reading this book, you will:


  • Gain a deeper understanding of how C++ works under the hood



  • Learn how to write code that is clear, correct, efficient, and portable



  • Avoid common mistakes and misconceptions that can lead to bugs and bad performance



  • Discover new techniques and features that can make your code more expressive and powerful



  • Challenge yourself with interesting and realistic problems that test your knowledge and creativity



  • Have fun and enjoy the beauty and complexity of C++



Main Content




Part I: Generic Programming and the C++ Standard Library




The first part of the book covers topics related to generic programming and the C++ standard library. Generic programming is a paradigm that allows you to write code that can work with different types of data, without having to write separate versions for each type. The C++ standard library provides a set of generic containers, algorithms, iterators, and functions that can help you write generic code more easily and efficiently.


In this part, you will learn how to:


  • Distinguish between pointers and references, and when to use each one



  • Prefer const and inline to #define, and why macros are evil



  • Avoid using new and delete directly, and use smart pointers instead



  • Use vector and string instead of arrays, and why arrays are evil



  • Use template functions for generic algorithms, and how to write your own templates



Item 1: Distinguish between pointers and references




A pointer is a variable that holds the address of another variable. A reference is an alias for another variable. Both pointers and references allow you to access or modify the value of another variable indirectly. However, they have some important differences that you need to be aware of:


PointersReferences


Can be null or point to nothingCannot be null or refer to nothing


Can be reassigned to point to different variablesCannot be reassigned to refer to different variables


Need to be dereferenced with * or -> to access or modify the value they point toDo not need to be dereferenced; they act as if they were the variable they refer to


Can point to or refer to const or non-const variables, depending on whether they are declared as const or non-const pointersCan only refer to const variables if they are declared as const references; otherwise, they can only refer to non-const variables


Can be used as parameters for functions that need to modify their arguments or return multiple values; however, they need to be checked for null before using themCan also be used as parameters for functions that need to modify their arguments or return multiple values; however, they do not need to be checked for null because they are guaranteed to be valid


```html they should not be used to return a reference to a local variable that goes out of scope when the function returns


As a general rule, you should prefer references over pointers whenever possible, because they are safer and easier to use. However, there are some situations where pointers are necessary or more convenient, such as:


  • When you need to represent the absence of a value or an optional value



  • When you need to perform pointer arithmetic or access memory directly



  • When you need to work with dynamic arrays or polymorphic objects



  • When you need to implement data structures that use pointers internally, such as linked lists or trees



Item 2: Prefer const and inline to #define




In C++, you can use the #define directive to create macros that replace a name with a value or an expression. For example:


#define PI 3.14 #define SQUARE(x) ((x) * (x))


However, using macros has several drawbacks and risks, such as:


  • Macros are not subject to scope rules or type checking; they can cause name collisions or type errors that are hard to debug



  • Macros can have unintended side effects or unexpected results; for example, SQUARE(++x) will increment x twice instead of once



  • Macros can make the code less readable and maintainable; they can hide the actual meaning or logic of the code



  • Macros can interfere with the debugging process; they can prevent the debugger from showing the correct values or locations of variables or expressions



Therefore, you should avoid using macros whenever possible, and use const and inline instead. Const and inline are keywords that allow you to define constants and functions that have similar benefits as macros, but without the drawbacks. For example:


const double PI = 3.14; inline double square(double x) return x * x;


By using const and inline, you can:


  • Ensure that your constants and functions are scoped and typed correctly; they can avoid name collisions or type errors



  • Ensure that your constants and functions have no side effects or unexpected results; they can behave as expected



  • Improve the readability and maintainability of your code; they can make the code more clear and consistent



  • Facilitate the debugging process; they can allow the debugger to show the correct values or locations of variables or expressions



The only exception where you might still need to use #define is when you need to create conditional compilation directives, such as #ifdef or #ifndef. These directives allow you to include or exclude parts of your code depending on certain conditions, such as the platform or the compiler. However, you should use them sparingly and carefully, because they can also make your code less portable and more complex.


Item 3: Avoid using new and delete directly




In C++, you can use the new and delete operators to allocate and deallocate memory dynamically. For example:


int* p = new int(42); // allocate an int on the heap and initialize it to 42 delete p; // deallocate the int from the heap


However, using new and delete directly has several disadvantages and dangers, such as:


  • You have to remember to delete every object that you allocate with new; otherwise, you will cause memory leaks that waste resources and degrade performance



  • You have to make sure that you delete every object exactly once; otherwise, you will cause undefined behavior that can corrupt memory and crash your program



  • You have to handle exceptions properly; otherwise, you will cause memory leaks or undefined behavior if an exception is thrown before you delete an object



  • You have to deal with low-level details of memory management; otherwise, you will make your code more complicated and error-prone



Therefore, you should avoid using new and delete directly whenever possible, and use smart pointers instead. Smart pointers are classes that wrap a raw pointer and manage its lifetime automatically. They use a technique called RAII (Resource Acquisition Is Initialization) to ensure that the object pointed by the smart pointer is deleted when the smart pointer goes out of scope or is reassigned. For example:


#include


std::unique_ptr p(new int(42)); // allocate an int on the heap and initialize it to 42 // no need to delete p; it will be deleted automatically when p goes out of scope or is reassigned


By using smart pointers, you can:


  • Prevent memory leaks and undefined behavior; the smart pointer will delete the object for you



  • Simplify exception handling; the smart pointer will delete the object for you even if an exception is thrown



  • Abstract away the low-level details of memory management; the smart pointer will handle them for you



The C++ standard library provides several types of smart pointers, such as std::unique_ptr, std::shared_ptr, and std::weak_ptr. Each type has its own semantics and use cases, depending on how you want to share or transfer ownership of the object. You should choose the appropriate type of smart pointer for your situation, and follow the guidelines and best practices for using them correctly.


Item 4: Use vector and string instead of arrays




In C++, you can use arrays to store a sequence of elements of the same type. For example:


int a[10]; // declare an array of 10 ints a[0] = 1; // assign 1 to the first element a[9] = 10; // assign 10 to the last element


However, using arrays has several limitations and risks, such as:


  • You have to specify the size of the array at compile time; you cannot resize or expand the array at run time



  • You have to pass the size of the array along with the array when you pass it to a function; otherwise, the function will not know how many elements are in the array



  • You have to be careful with array decay; when you pass an array to a function, it decays into a pointer to its first element, losing its size information



  • You have to avoid buffer overflow; when you access an element of an array, you have to make sure that the index is within the bounds of the array, otherwise you will access invalid memory



  • You have to manage the lifetime of an array; if you allocate an array on the heap with new[], you have to deallocate it with delete[]; if you allocate an array on the stack, it will be destroyed when it goes out of scope



Therefore, you should avoid using arrays whenever possible, and use vector and string instead. Vector and string are classes that represent dynamic arrays that can grow and shrink as needed. They are part of the C++ standard library, and they provide many features and benefits that arrays do not. For example:


#include


#include


std::vector v; // declare a vector of ints v.push_back(1); // append 1 to the end of the vector v.push_back(10); // append 10 to the end of the vector std::string s; // declare a string s += "Hello"; // append "Hello" to the end of the string s += " world"; // append " world" to the end of the string


By using vector and string, you can:


  • Resize or expand your sequence as needed at run time; vector and string will allocate or deallocate memory for you as necessary



  • Pass your sequence to a function without passing its size; vector and string have member functions that can tell you how many elements are in them



  • Avoid array decay; when you pass a vector or a string to a function, it will not decay into a pointer; it will retain its type and size information



  • Avoid buffer overflow; vector and string have bounds checking mechanisms that can prevent you from accessing invalid memory; they also have iterators that can help you traverse them safely



  • Avoid managing the lifetime of your sequence; vector and string use RAII to manage their memory automatically; they will be destroyed when they go out of scope or are reassigned



In addition, vector and string also provide many other features and benefits that arrays do not, such as:


  • They can store any type of elements, not just primitive types; they can store user-defined types, such as classes or structs



  • They can work with generic algorithms from the standard library, such as sort or find; they can also provide their own algorithms, such as erase or replace



  • They can support different operations and interfaces, such as insertion, deletion, concatenation, comparison, or conversion



```html They can support different operations and interfaces, such as insertion, deletion, concatenation, comparison, or conversion


  • They can be initialized or assigned with different syntaxes, such as initializer lists, range constructors, or copy constructors



  • They can be compatible with C-style arrays or strings, such as using data() or c_str() to get a pointer to their underlying array



The only exception where you might still need to use arrays is when you need to interface with legacy code or libraries that expect C-style arrays or strings. In that case, you can use vector or string to create and manipulate your sequence, and then convert it to an array or a string when you need to pass it to the external code or library.


Item 5: Use template functions for generic algorithms




In C++, you can use template functions to write generic algorithms that can work with different types of data. A template function is a function that takes one or more template parameters that represent the types of the data. The template parameters are enclosed in angle brackets () after the function name. For example:


template


T max(T x, T y) return x > y ? x : y;


This is a template function that takes two arguments of type T and returns the maximum of them. The type T is a template parameter that can be any type that supports the > operator. For example:


int a = 10; int b = 20; int c = max(a, b); // c is 20; T is int double d = 3.14; double e = 2.71; double f = max(d, e); // f is 3.14; T is double std::string g = "Hello"; std::string h = "World"; std::string i = max(g, h); // i is "World"; T is std::string


By using template functions, you can:


  • Write generic code that can work with different types of data, without having to write separate versions for each type



  • Avoid code duplication and inconsistency; you only need to write and maintain one version of the algorithm



  • Improve performance and efficiency; the compiler will generate a specialized version of the algorithm for each type at compile time



  • Enhance readability and maintainability; you only need to understand and document one version of the algorithm



The C++ standard library provides many template functions that implement common and useful algorithms, such as sort, find, count, accumulate, transform, and more. You can use these template functions to perform various operations on your data, such as sorting, searching, counting, summing, modifying, and more. You can also write your own template functions to implement your own algorithms.


When writing template functions, you should follow some guidelines and best practices, such as:


  • Use typename instead of class for template parameters; they are equivalent in meaning, but typename is more clear and consistent



  • Use descriptive names for template parameters; avoid using single letters or generic names like T or U; use names that reflect the role or concept of the parameter



  • Use const references for parameters that are not modified by the algorithm; this can avoid unnecessary copying and allow the algorithm to work with non-copyable types



  • Use iterator parameters for sequences of elements; this can make the algorithm more generic and flexible; it can work with any type of container that supports iterators



  • Use function objects or lambdas for predicates or actions; this can make the algorithm more customizable and expressive; it can accept any type of callable object that matches the expected signature



  • Use enable_if or concepts (in C++20) for constraints or requirements; this can make the algorithm more robust and safe; it can check if the types passed to the algorithm satisfy certain conditions or support certain operations



Part II: Exception Safety Issues and Techniques




The second part of the book covers topics related to exception safety and techniques. Exception safety is a property of code that guarantees that it will not cause any unwanted effects or leaks when an exception is thrown. An exception is an event that occurs when something goes wrong during the execution of a program. C++ provides a mechanism for throwing and catching exceptions using the keywords throw and catch. For example:


void foo() throw std::runtime_error("Something went wrong in foo"); void bar() try foo(); catch (const std::exception& e) std::cout


This is an example of a function that throws an exception of type std::runtime_error, and a function that catches the exception and handles it. When an exception is thrown, the program will unwind the stack and look for a matching catch block that can


About

Welcome to the group! You can connect with other members, ge...

Members

  • nyedera moreland
  • Reda Na
    Reda Na
  • Orest Maximov
    Orest Maximov
  • Angel Hill
    Angel Hill
  • Cooper Thompson
    Cooper Thompson
bottom of page