Praise for Effective Modern C++

Praise for Effective Modern C++

So, still interested in C++? You should be! Modern C++ (i.e., C++11/C++14) is far more than just a facelift. Considering the new features, it seems that it’s more a reinvention. Looking for guidelines and assistance? Then this book is surely what you are looking for. Concerning C++, Scott Meyers was and still is a synonym for accuracy, quality, and delight.

Gerhard Kreuzer

Research and Development Engineer, Siemens AG

Finding utmost expertise is hard enough. Finding teaching perfectionism — an author’s obsession with strategizing and streamlining explanations — is also difficult. You know you’re in for a treat when you get to find both embodied in the same person. Effective Modern C++ is a towering achievement from a consummate technical writer. It layers lucid, meaningful, and well-sequenced clarifications on top of complex and interconnected topics, all in crisp literary style. You’re equally unlikely to find a technical mistake, a dull moment, or a lazy sentence in Effective Modern C++.

Andrei Alexandrescu

Ph.D., Research Scientist, Facebook, and author of Modern C++ Design

As someone with over two decades of C++ experience, to get the most out of modern C++ (both best practices and pitfalls to avoid), I highly recommend getting this book, reading it thoroughly, and referring to it often! I’ve certainly learned new things going through it!

Nevin Liber

Senior Software Engineer, DRW Trading Group

Bjarne Stroustrup — the creator of C++ — said, “C++11 feels like a new language.” Effective Modern C++ makes us share this same feeling by clearly explaining how everyday programmers can benefit from new features and idioms of C++11 and C++14. Another great Scott Meyers book.

Cassio Neri

FX Quantitative Analyst, Lloyds Banking Group

Scott has the knack of boiling technical complexity down to an understandable kernel. His Effective C++ books helped to raise the coding style of a previous generation of C++ programmers; the new book seems positioned to do the same for those using modern C++.

Roger Orr

OR/2 Limited, a member of the ISO C++ standards committee

Effective Modern C++ is a great tool to improve your modern C++ skills. Not only does it teach you how, when and where to use modern C++ and be effective, it also explains why. Without doubt, Scott’s clear and insightful writing, spread over 42 well-thought items, gives programmers a much better understanding of the language.

Bart Vandewoestyne

Research and Development Engineer and C++ enthusiast

I love C++, it has been my work vehicle for many decades now. And with the latest raft of features it is even more powerful and expressive than I would have previously imagined. But with all this choice comes the question “when and how do I apply these features?” As has always been the case, Scott’s Effective C++ books are the definitive answer to this question.

Damien Watkins

Computation Software Engineering Team Lead, CSIRO

Great read for transitioning to modern C++ — new C++11/14 language features are described alongside C++98, subject items are easy to reference, and advice summarized at the end of each section. Entertaining and useful for both casual and advanced C++ developers.

Rachel Cheng

F5 Networks

If you’re migrating from C++98/03 to C++11/14, you need the eminently practical and clear information Scott provides in Effective Modern C++. If you’re already writing C++11 code, you’ll probably discover issues with the new features through Scott’s thorough discussion of the important new features of the language. Either way, this book is worth your time.

Rob Stewart

Boost Steering Committee member (boost.org)

Effective Modern C++

Scott Meyers

Effective Modern C++

by Scott Meyers

Copyright © 2015 Scott Meyers. All rights reserved.

Printed in Canada.

Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.

O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://safaribooksonline.com). For more information, contact our corporate/institutional sales department: 800-998-9938 or corporate@oreilly.com.

- Editor: Rachel Roumeliotis

- Production Editor: Melanie Yarbrough

- Copyeditor: Jasmine Kwityn

- Proofreader: Charles Roumeliotis

- Indexer: Scott Meyers

- Interior Designer: David Futato

- Cover Designer: Ellie Volkhausen

- Illustrator: Rebecca Demarest

- November 2014: First Edition

Revision History for the First Edition

- 2014-11-07: First Release

- 2014-12-12: Second Release

- 2015-01-20: Third Release

- 2015-04-03: Fourth Release

See http://oreilly.com/catalog/errata.csp?isbn=9781491903995 for release details.

The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. Effective Modern C++, the cover image of a Rose-crowned Fruit Dove, and related trade dress are trademarks of O’Reilly Media, Inc.

While the publisher and the author have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the author disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights.

978-1-491-90399-5

[TI]

For Darla,

black Labrador Retriever extraordinaire

Chapter 1. Moving to Modern C++

When it comes to big-name features, C++11 and C++14 have a lot to boast of. auto, smart pointers, move semantics, lambdas, concurrency — each is so important, I devote a chapter to it. It’s essential to master those features, but becoming an effective modern C++ programmer requires a series of smaller steps, too. Each step answers specific questions that arise during the journey from C++98 to modern C++. When should you use braces instead of parentheses for object creation? Why are alias declarations better than typedefs? How does constexpr differ from const? What’s the relationship between const member functions and thread safety? The list goes on and on. And one by one, this chapter provides the answers.

Item 14: Declare functions noexcept if they won’t emit exceptions.

In C++98, exception specifications were rather temperamental beasts. You had to summarize the exception types a function might emit, so if the function’s implementation was modified, the exception specification might require revision, too. Changing an exception specification could break client code, because callers might be dependent on the original exception specification. Compilers typically offered no help in maintaining consistency among function implementations, exception specifications, and client code. Most programmers ultimately decided that C++98 exception specifications weren’t worth the trouble.

During work on C++11, a consensus emerged that the truly meaningful information about a function’s exception-emitting behavior was whether it had any. Black or white, either a function might emit an exception or it guaranteed that it wouldn’t. This maybe-or-never dichotomy forms the basis of C++11’s exception specifications, which essentially replace C++98’s. (C++98-style exception specifications remain valid, but they’re deprecated.) In C++11, unconditional noexcept is for functions that guarantee they won’t emit exceptions.

Whether a function should be so declared is a matter of interface design. The exception-emitting behavior of a function is of key interest to clients. Callers can query a function’s noexcept status, and the results of such a query can affect the exception safety or efficiency of the calling code. As such, whether a function is noexcept is as important a piece of information as whether a member function is const. Failure to declare a function noexcept when you know that it won’t emit an exception is simply poor interface specification.

But there’s an additional incentive to apply noexcept to functions that won’t produce exceptions: it permits compilers to generate better object code. To understand why, it helps to examine the difference between the C++98 and C++11 ways of saying that a function won’t emit exceptions. Consider a function f that promises callers they’ll never receive an exception. The two ways of expressing that are:

int f(int x) throw();     // no exceptions from f: C++98 style

int f(int x) noexcept;    // no exceptions from f: C++11 style

If, at runtime, an exception leaves f, f’s exception specification is violated. With the C++98 exception specification, the call stack is unwound to f’s caller, and, after some actions not relevant here, program execution is terminated. With the C++11 exception specification, runtime behavior is slightly different: the stack is only possibly unwound before program execution is terminated.

The difference between unwinding the call stack and possibly unwinding it has a surprisingly large impact on code generation. In a noexcept function, optimizers need not keep the runtime stack in an unwindable state if an exception would propagate out of the function, nor must they ensure that objects in a noexcept function are destroyed in the inverse order of construction should an exception leave the function. Functions with “throw()” exception specifications lack such optimization flexibility, as do functions with no exception specification at all. The situation can be summarized this way:

RetType function(params) noexcept;     // most optimizable

RetType function(params) throw();      // less optimizable

RetType function(params);              // less optimizable

This alone is sufficient reason to declare functions noexcept whenever you know they won’t produce exceptions.

For some functions, the case is even stronger. The move operations are the preeminent example. Suppose you have a C++98 code base making use of a std::vector<Widget>. Widgets are added to the std::vector from time to time via push_back:

std::vector<Widget> vw;

…

Widget w;

…                        // work with w

vw.push_back(w);         // add w to vw

…

Assume this code works fine, and you have no interest in modifying it for C++11. However, you do want to take advantage of the fact that C++11’s move semantics can improve the performance of legacy code when move-enabled types are involved. You therefore ensure that Widget has move operations, either by writing them yourself or by seeing to it that the conditions for their automatic generation are fulfilled (see Item 17).

When a new element is added to a std::vector, it’s possible that the std::vector lacks space for it, i.e., that the std::vector’s size is equal to its capacity. When that happens, the std::vector allocates a new, larger, chunk of memory to hold its elements, and it transfers the elements from the existing chunk of memory to the new one. In C++98, the transfer was accomplished by copying each element from the old memory to the new memory, then destroying the objects in the old memory. This approach enabled push_back to offer the strong exception safety guarantee: if an exception was thrown during the copying of the elements, the state of the std::vector remained unchanged, because none of the elements in the old memory were destroyed until all elements had been successfully copied into the new memory.

In C++11, a natural optimization would be to replace the copying of std::vector elements with moves. Unfortunately, doing this runs the risk of violating push_back’s exception safety guarantee. If n elements have been moved from the old memory and an exception is thrown moving element n+1, the push_back operation can’t run to completion. But the original std::vector has been modified: n of its elements have been moved from. Restoring their original state may not be possible, because attempting to move each object back into the original memory may itself yield an exception.

This is a serious problem, because the behavior of legacy code could depend on push_back’s strong exception safety guarantee. Therefore, C++11 implementations can’t silently replace copy operations inside push_back with moves unless it’s known that the move operations won’t emit exceptions. In that case, having moves replace copies would be safe, and the only side effect would be improved performance.

std::vector::push_back takes advantage of this “move if you can, but copy if you must” strategy, and it’s not the only function in the Standard Library that does. Other functions sporting the strong exception safety guarantee in C++98 (e.g., std::vector::reserve, std::deque::insert, etc.) behave the same way. All these functions replace calls to copy operations in C++98 with calls to move operations in C++11 only if the move operations are known to not emit exceptions. But how can a function know if a move operation won’t produce an exception? The answer is obvious: it checks to see if the operation  is declared noexcept.[1]

swap functions comprise another case where noexcept is particularly desirable. swap is a key component of many STL algorithm implementations, and it’s commonly employed in copy assignment operators, too. Its widespread use renders the optimizations that noexcept affords especially worthwhile. Interestingly, whether swaps in the Standard Library are noexcept is sometimes dependent on whether user-defined swaps are noexcept. For example, the declarations for the Standard Library’s swaps for arrays and std::pair are:

template <class T, size_t N>
void swap(T (&a)[N],                                    // see
T (&b)[N]) noexcept(noexcept(swap(*a, *b)));  // below

template <class T1, class T2>
struct pair {
…
void swap(pair& p) noexcept(noexcept(swap(first, p.first)) &&
noexcept(swap(second, p.second)));
…
};

These functions are conditionally noexcept: whether they are noexcept depends on whether the expressions inside the noexcept clauses are noexcept. Given two arrays of Widget, for example, swapping them is noexcept only if swapping individual elements in the arrays is noexcept, i.e., if swap for Widget is noexcept. The author of Widget’s swap thus determines whether swapping arrays of Widget is noexcept. That, in turn, determines whether other swaps, such as the one for arrays of arrays of Widget, are noexcept. Similarly, whether swapping two std::pair objects containing Widgets is noexcept depends on whether swap for Widgets is noexcept. The fact that swapping higher-level data structures can generally be noexcept only if swapping their lower-level constituents is noexcept should motivate you to offer noexcept swap functions whenever you can.

By now, I hope you’re excited about the optimization opportunities that noexcept affords. Alas, I must temper your enthusiasm. Optimization is important, but correctness is more important. I noted at the beginning of this Item that noexcept is part of a function’s interface, so you should declare a function noexcept only if you are willing to commit to a noexcept implementation over the long term. If you declare a function noexcept and later regret that decision, your options are bleak. You can remove noexcept from the function’s declaration (i.e., change its interface), thus running the risk of breaking client code. You can change the implementation such that an exception could escape, yet keep the original (now incorrect) exception specification. If you do that, your program will be terminated if an exception tries to leave the function. Or you can resign yourself to your existing implementation, abandoning whatever kindled your desire to change the implementation in the first place. None of these options is appealing.

The fact of the matter is that most functions are exception-neutral. Such functions throw no exceptions themselves, but functions they call might emit one. When that happens, the exception-neutral function allows the emitted exception to pass through on its way to a handler further up the call chain. Exception-neutral functions are never noexcept, because they may emit such “just passing through” exceptions. Most functions, therefore, quite properly lack the noexcept designation.

Some functions, however, have natural implementations that emit no exceptions, and for a few more — notably the move operations and swap — being noexcept can have such a significant payoff, it’s worth implementing them in a noexcept manner if at all possible.[2] When you can honestly say that a function should never emit exceptions, you should definitely declare it noexcept.

Please note that I said some functions have natural noexcept implementations. Twisting a function’s implementation to permit a noexcept declaration is the tail wagging the dog. Is putting the cart before the horse. Is not seeing the forest for the trees. Is…choose your favorite metaphor. If a straightforward function implementation might yield exceptions (e.g., by invoking a function that might throw), the hoops you’ll jump through to hide that from callers (e.g., catching all exceptions and replacing them with status codes or special return values) will not only complicate your function’s implementation, it will typically complicate code at call sites, too. For example, callers may have to check for status codes or special return values. The runtime cost of those complications (e.g., extra branches, larger functions that put more pressure on instruction caches, etc.) could exceed any speedup you’d hope to achieve via noexcept, plus you’d be saddled with source code that’s more difficult to comprehend and maintain. That’d be poor software engineering.

For some functions, being noexcept is so important, they’re that way by default. In C++98, it was considered bad style to permit the memory deallocation functions (i.e., operator delete and operator delete[]) and destructors to emit exceptions, and in C++11, this style rule has been all but upgraded to a language rule. By default, all memory deallocation functions and all destructors — both user-defined and compiler-generated — are implicitly noexcept. There’s thus no need to declare them noexcept. (Doing so doesn’t hurt anything, it’s just unconventional.) The only time a destructor is not implicitly noexcept is when a data member of the class (including inherited members and those contained inside other data members) is of a type that expressly states that its destructor may emit exceptions (e.g., declares it “noexcept(false)”). Such destructors are uncommon. There are none in the Standard Library, and if the destructor for an object being used by the Standard Library (e.g., because it’s in a container or was passed to an algorithm) emits an exception, the behavior of the program is undefined.

It’s worth noting that some library interface designers distinguish functions with wide contracts from those with narrow contracts. A function with a wide contract has no preconditions. Such a function may be called regardless of the state of the program, and it imposes no constraints on the arguments that callers pass it.[3] Functions with wide contracts never exhibit undefined behavior.

Functions without wide contracts have narrow contracts. For such functions, if a precondition is violated, results are undefined.

If you’re writing a function with a wide contract and you know it won’t emit exceptions, following the advice of this Item and declaring it noexcept is easy. For functions with narrow contracts, the situation is trickier. For example, suppose you’re writing a function f taking a std::string parameter, and suppose f’s natural implementation never yields an exception. That suggests that f should be declared noexcept.

Now suppose that f has a precondition: the length of its std::string parameter doesn’t exceed 32 characters. If f were to be called with a std::string whose length is greater than 32, behavior would be undefined, because a precondition violation by definition results in undefined behavior. f is under no obligation to check this precondition, because functions may assume that their preconditions are satisfied. (Callers are responsible for ensuring that such assumptions are valid.) Even with a precondition, then, declaring f noexcept seems appropriate:

void f(const std::string& s) noexcept;    // precondition:
// s.length() <= 32

But suppose that f’s implementer chooses to check for precondition violations. Checking isn’t required, but it’s also not forbidden, and checking the precondition could be useful, e.g., during system testing. Debugging an exception that’s been thrown is generally easier than trying to track down the cause of undefined behavior. But how should a precondition violation be reported such that a test harness or a client error handler could detect it? A straightforward approach would be to throw a “precondition was violated” exception, but if f is declared noexcept, that would be impossible; throwing an exception would lead to program termination. For this reason, library designers who distinguish wide from narrow contracts generally reserve noexcept for functions with wide contracts.

As a final point, let me elaborate on my earlier observation that compilers typically offer no help in identifying inconsistencies between function implementations and their exception specifications. Consider this code, which is perfectly legal:

void setup();           // functions defined elsewhere
void cleanup();

void doWork() noexcept
{
setup();              // set up work to be done

…                     // do the actual work

cleanup();            // perform cleanup actions
}

Here, doWork is declared noexcept, even though it calls the non-noexcept functions setup and cleanup. This seems contradictory, but it could be that setup and cleanup document that they never emit exceptions, even though they’re not declared that way. There could be good reasons for their non-noexcept declarations. For example, they might be part of a library written in C. (Even functions from the C Standard Library that have been moved into the std namespace lack exception specifications, e.g., std::strlen isn’t declared noexcept.) Or they could be part of a C++98 library that decided not to use C++98 exception specifications and hasn’t yet been revised for C++11.

Because there are legitimate reasons for noexcept functions to rely on code lacking the noexcept guarantee, C++ permits such code, and compilers generally don’t issue warnings about it.

Things to Remember

- noexcept is part of a function’s interface, and that means that callers may depend on it.

- noexcept functions are more optimizable than non-noexcept functions.

- noexcept is particularly valuable for the move operations, swap, memory deallocation functions, and destructors.

- Most functions are exception-neutral rather than noexcept.

[1] The checking is typically rather roundabout. Functions like std::vector::push_back call std::move_if_noexcept, a variation of std::move that conditionally casts to an rvalue (see Item 23), depending on whether the type’s move constructor is noexcept. In turn, std::move_if_noexcept consults std::is_nothrow_move_constructible, and the value of this type trait (see Item 9) is set by compilers, based on whether the move constructor has a noexcept (or throw()) designation.

[2] The interface specifications for move operations on containers in the Standard Library lack noexcept. However, implementers are permitted to strengthen exception specifications for Standard Library functions, and, in practice, it is common for at least some container move operations to be declared noexcept. That practice exemplifies this Item’s advice. Having found that it’s possible to write container move operations such that exceptions aren’t thrown, implementers often declare the operations noexcept, even though the Standard does not require them to do so.

[3] “Regardless of the state of the program” and “no constraints” doesn’t legitimize programs whose behavior is already undefined. For example, std::vector::size has a wide contract, but that doesn’t require that it behave reasonably if you invoke it on a random chunk of memory that you’ve cast to a std::vector. The result of the cast is undefined, so there are no behavioral guarantees for the program containing the cast.

1. Want to read more?

2. Copyright/Revision History

3. 1. Moving to Modern C++

1. Item 14: Declare functions noexcept if they won’t emit exceptions.

4. O’Reilly Ebooks