Search for notes by fellow students, in your own course and all over the country.

Browse our notes for titles which look like what you need, you can preview any of the notes via a sample of the contents. After you're happy these are the notes you're after simply pop them into your shopping cart.

My Basket

You have nothing in your shopping cart yet.

Title: C++ Programme By-bjarne stroustrup
Description: This Book contains all the necessary details of C++ Programme and.......all the information about C++ are present in this book......this book a contains all the important programmes that a computer programmer should know............so..........i hope this book is very beneficial for you...........Thank you........

Document Preview

Extracts from the notes are below, to see the PDF you'll receive please use the links above


The
C++
Programming
Language
Fourth Edition

Bjarne Stroustrup

Upper Saddle River, NJ • Boston • Indianapolis • San Francisco
New York • Totonto • Montreal • London • Munich • Paris • Madrid
Capetown • Sydney • Tokyo • Singapore • Mexico City

Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks
...

The author and publisher have taken care in the preparation of this book, but make no expressed or implied warranty of any
kind and assume no responsibility for errors or omissions
...

The publisher offers excellent discounts on this book when ordered in quantity for bulk purchases or special sales, which
may include electronic versions and/or custom covers and content particular to your business, training goals, marketing
focus, and branding interests
...
S
...
com
For sales outside the United States, please contact:
International Sales
international@pearsoned
...
com/aw
Library of Congress Cataloging-in-Publication Data
Stroustrup, Bjarne
...
—Fourth edition
...

ISBN 978-0-321-56384-2 (pbk
...
paper)—ISBN 0-321-56384-0 (pbk
...
paper)
1
...
Title
...
73
...
13’3—dc23

2013002159

Copyright © 2013 by Pearson Education, Inc
...
Printed in the United States of America
...
To obtain permission to use material
from this work, please submit a written request to Pearson Education, Inc
...

This book was typeset in Times and Helvetica by the author
...

Second printing, June 2013

Contents

Contents

iii

Preface

v
Preface to the Fourth Edition
...
ix
Preface to the Second Edition
...
xii

Part I: Introductory Material
1
...

3
...

5
...
3
A Tour of C++: The Basics
...
59
A Tour of C++: Containers and Algorithms
...
111

Part II: Basic Facilities
6
...

8
...

10
...
135
Pointers, Arrays, and References
...
201
Statements
...
241

133

iv

Contents

11
...

13
...

15
...
273
Functions
...
343
Namespaces
...
419

Part III: Abstraction Mechanisms
16
...

18
...

20
...

22
...

24
...

26
...

28
...


Classes
...
481
Overloading
...
549
Derived Classes
...
613
Run-Time Type Information
...
665
Generic Programming
...
721
Instantiation
...
759
Metaprogramming
...
827

Part IV: The Standard Library
30
...

32
...

34
...

36
...

38
...

40
...

42
...

44
...
859
STL Containers
...
927
STL Iterators
...
973
Utilities
...
1033
Regular Expressions
...
1073
Locales
...
1159
Concurrency
...
1209
The C Standard Library
...
1267
1281

Preface
All problems in computer science
can be solved by another level of indirection,
except for the problem of too many layers of indirection
...
Wheeler

C++ feels like a new language
...
Furthermore, the resulting programs are better
checked by the compiler and run faster
...
I describe every language feature and standard-library
component that a professional programmer is likely to need
...

• Examples: How can it be used well by itself and in combination with other features? What
are the key techniques and idioms? What are the implications for maintainability and performance?
The use of C++ has changed dramatically over the years and so has the language itself
...
The current ISO
standard C++ (ISO/IEC 14882-2011, usually called C++11) is simply a far better tool for writing
quality software than were previous versions
...
Many answers are not the
same as you would find with 1985, 1995, or 2005 vintage C++: progress happens
...
It is particularly suited for resource-constrained applications, such as
those found in software infrastructures
...
C++ is a language for someone who takes the task of programming seriously
...

There are billions of lines of C++ deployed
...
However, for all applications,
you can do better with modern C++; if you stick to older styles, you will be writing lower-quality
and worse-performing code
...
All code in this book conforms
to the 2011 ISO C++ standard
...

Naturally, these three groups are not disjoint – a professional software developer masters more than
just one programming language
...
If you ask, ‘‘What’s a for-loop?’’ or
‘‘What’s a compiler?’’ then this book is not (yet) for you; instead, I recommend my Programming:
Principles and Practice Using C++ to get started with programming and C++
...
If you ask ‘‘Why bother testing?’’
or say, ‘‘All languages are basically the same; just show me the syntax’’ or are confident that there
is a single language that is ideal for every task, this is not the book for you
...
Language and standard-library facilities for doing systemslevel concurrent programming (e
...
, using multicores)
...

General and uniform initialization, a simpler for-statement, move semantics, basic Unicode support,
lambdas, general constant expressions, control over class defaults, variadic templates, user-defined
literals, and more
...
They are meant to be used in combination –
as bricks in a building set – rather than to be used individually in relative isolation to solve a specific problem
...
In particular,
C++’s design aims to be sufficiently flexible and general to cope with future problems undreamed
of by its designers
...
Boehm, Marshall Clow, Jonathan Coe, Lawrence Crowl,
Walter Daugherty, J
...
Without their help this book would have been much poorer
...

Andrew Sutton is the author of the Origin library, which was the testbed for much of the discussion of emulating concepts in the template chapters, and of the matrix library that is the topic of
Chapter 29
...
’’
Thanks to my graduate design class for finding more problems with the ‘‘tour chapters’’ than
anyone else
...
Every expert
reviewer suggested adding technical details, advanced examples, and many useful development
conventions; every novice reviewer (or educator) suggested adding examples; and most reviewers
observed (correctly) that the book may be too long
...
Brian
Kernighan, for hosting me for part of the sabbatical that gave me time to write this book
...
Andy Hopper, for hosting me for part of the sabbatical that gave me time to write this book
...

College Station, Texas

Bjarne Stroustrup

This page intentionally left blank

Preface to the Third Edition
Programming is understanding
...
C++’s support for design and programming has
improved dramatically over the years, and lots of new helpful techniques have been developed for
its use
...
Ordinary practical programmers have achieved significant
improvements in productivity, maintainability, flexibility, and quality in projects of just about any
kind and scale
...

This book introduces standard C++† and the key programming and design techniques supported
by C++
...
New language features such as namespaces, exceptions,
templates, and run-time type identification allow many techniques to be applied more directly than
was possible before, and the standard library allows the programmer to start from a much higher
level than the bare language
...
This
third edition is the result of a rewrite of even larger magnitude
...
The explosion of C++ use and the massive amount of experience accumulated as a result makes this possible
...
As before, this book presents C++ independently of any particular implementation,
and as before, the tutorial chapters present language constructs and concepts in a ‘‘bottom up’’
order so that a construct is used only after it has been defined
...
Therefore, the standard library can be used to provide realistic and interesting examples well before a reader can be
assumed to understand its inner workings
...

This book presents every major C++ language feature and the standard library
...
However, features are presented in the context of their use
...


x

Preface to the Third Edition

That is, the focus is on the language as the tool for design and programming rather than on the language in itself
...
Except where illustrating technicalities, examples are
taken from the domain of systems software
...

The primary aim of this book is to help the reader understand how the facilities offered by C++
support key programming techniques
...
Only a good understanding of the ideas behind the language facilities leads to
mastery
...
The hope is that this book will help the reader gain
new insights and become a better programmer and designer
...
Without their help and suggestions, this book would have been harder to understand, contained more
errors, been slightly less complete, and probably been a little bit shorter
...
It is slightly unfair to single out individuals, but it would be even more unfair not to mention anyone, so I’d like to especially mention
Mike Ball, Dag Br¨ ck, Sean Corfield, Ted Goldstein, Kim Knuttila, Andrew Koenig, Dmitry
u
Lenkov, Nathan Myers, Martin O’Riordan, Tom Plum, Jonathan Shopiro, John Spicer, Jerry
Schwarz, Alex Stepanov, and Mike Vilot, as people who each directly cooperated with me over
some part of C++ and its standard library
...
I have been able to accommodate many of their suggestions within
the framework of the book so that later printings benefitted significantly
...
In response to requests from readers, I
have added appendices D and E
...
Sevinc, Andy Tenne-Sens, Shoichi Uchida,
u
¸
Ping-Fai (Mike) Yang, and Dennis Yelle
...

– Bilbo Baggins

As promised in the first edition of this book, C++ has been evolving to meet the needs of its users
...
The C++ user-community has grown a hundredfold during the
six years since the first edition of this book; many lessons have been learned, and many techniques
have been discovered and/or validated by experience
...

The primary aim of the language extensions made in the last six years has been to enhance C++
as a language for data abstraction and object-oriented programming in general and to enhance it as
a tool for writing high-quality libraries of user-defined types in particular
...
In this context, safe means that a class provides a specific
type-safe interface between the users of the library and its providers; efficient means that use of the
class does not impose significant overheads in run-time or space on the user compared with handwritten C code
...
Chapters 1 through 10 give a tutorial introduction; Chapters 11 through 13 provide a discussion of design and software development issues; and,
finally, the complete C++ reference manual is included
...
They include refined
overloading resolution, memory management facilities, and access control mechanisms, type-safe
linkage, const and static member functions, abstract classes, multiple inheritance, templates, and
exception handling
...
In addition, C++ is successfully used in many application areas
that are not covered by this label
...
Consequently,
this book describes the C++ language itself without trying to explain a particular implementation,
programming environment, or library
...
’’ This style of exposition allows general principles and useful techniques to stand out more
clearly than they would in a fully elaborated program, where they would be buried in details
...
, are available in ‘‘bulletproof ’’ and/or ‘‘goldplated’’ versions from a
wide variety of commercial and non-commercial sources
...

This edition provides a greater emphasis on tutorial aspects than did the first edition of this
book
...
The discussion of design issues has been greatly
expanded to reflect the demand for information beyond the description of language features and
their immediate use
...
The reference manual, in particular, represents many years of work in this direction
...
In
other words, this book presents the C++ language, its fundamental principles, and the key techniques needed to apply it
...
Many people influenced the development of C++ from 1985
to 1991
...
Also thanks to the many participants of the ‘‘external reviews’’ of the reference manual
drafts and to the people who suffered through the first year of X3J16
...

– B
...
Whorf

C++ is a general purpose programming language designed to make programming more enjoyable
for the serious programmer
...
In addition to the facilities provided by C, C++ provides flexible and efficient facilities for
defining new types
...
This technique for program construction is often called data abstraction
...

Such objects can be used conveniently and safely in contexts in which their type cannot be determined at compile time
...
When
used well, these techniques result in shorter, easier to understand, and easier to maintain programs
...
A class is a user-defined type
...
C++ provides
much better facilities for type checking and for expressing modularity than C does
...
C++ retains C’s ability to deal efficiently with the fundamental
objects of the hardware (bits, bytes, words, addresses, etc
...

C++ and its standard libraries are designed for portability
...
C libraries can be used from a C++ program, and most tools that
support programming in C can be used with C++
...
It provides a complete description of C++, many complete examples, and many
more program fragments
...
In particular, Tom Cargill, Jim Coplien, Stu Feldman, Sandy Fraser,
Steve Johnson, Brian Kernighan, Bart Locanthi, Doug McIlroy, Dennis Ritchie, Larry Rosler, Jerry
Schwarz, and Jon Shopiro provided important ideas for development of the language
...

In addition, hundreds of people contributed to the development of C++ and its compiler by
sending me suggestions for improvements, descriptions of problems they had encountered, and
compiler errors
...

Many people have also helped with the production of this book, in particular, Jon Bentley,
Laura Eaves, Brian Kernighan, Ted Kowalski, Steve Mahaney, Jon Shopiro, and the participants in
the C++ course held at Bell Labs, Columbus, Ohio, June 26-27, 1985
...
It also provides an overview of this book
and explains the approach taken to the description of the language facilities and their
use
...


Chapters
1
2
3
4
5

Notes to the Reader
A Tour of C++: The Basics
A Tour of C++: Abstraction Mechanisms
A Tour of C++: Containers and Algorithms
A Tour of C++: Concurrency and Utilities

2

Introduction

Part I

‘‘
...
Be many people
...
You
have worried too much about Marcus Cocoza, so that you have been really his slave
and prisoner
...
You were always much afraid that Marcus
might do a stupid thing, or be bored
...
I should like you to be easy, your little heart to
be light again
...
’’
– Karen Blixen,
The Dreamers from Seven Gothic Tales (1934)

1
Notes to the Reader
Hurry Slowly
(festina lente)
...
1 The Structure of This Book
A pure tutorial sorts its topics so that no concept is used before it has been introduced; it must be
read linearly starting with page one
...
A pure tutorial can in principle be read without prerequisites – it carefully describes all
...

This book combines aspects of both
...
If not, you can start at the beginning, but try not to
get bogged down in details
...


4

Notes to the Reader

Chapter 1

Making parts of the book relatively self-contained implies some repetition, but repetition also
serves as review for people reading the book linearly
...
Experienced programmers can read the (relatively) quick
‘‘tour’’ of C++ to gain the overview needed to use the book as a reference
...
Chapters 2-5 give a quick introduction to the C++ language
and its standard library
...

Part III
Abstraction Mechanisms: Chapters 16-29 describe C++’s abstraction mechanisms and their use for object-oriented and generic programming
...


1
...
1 Introduction
This chapter, Chapter 1, provides an overview of this book, some hints about how to use it, and
some background information about C++ and its use
...
Please do not feel
obliged to read it all carefully before proceeding
...

Chapter 3
A Tour of C++: Abstraction Mechanisms presents the language features supporting data abstraction, object-oriented programming, and generic programming
...

Chapter 5
A Tour of C++: Concurrency and Utilities outlines the standard-library utilities
related to resource management, concurrency, mathematical computation, regular expressions, and more
...
In particular, it should convince readers that C++ has come a long way since the first, second, and third editions of this book
...
1
...
It introduces the notions of type, object, scope, and storage
...
Modularity – as supported
by namespaces, source files, and exception handling – is also discussed:
Chapter 6
Types and Declarations: Fundamental types, naming, scopes, initialization, simple type deduction, object lifetimes, and type aliases

Section 1
...
2

Basic Facilities

5

Chapter 7
Chapter 8
Chapter 9

Pointers, Arrays, and References
Structures, Unions, and Enumerations
Statements: Declarations as statements, selection statements (if and switch), iteration statements (for, while, and do), goto, and comments
Chapter 10 Expressions: A desk calculator example, survey of operators, constant expressions, and implicit type conversion
...
For example,
I explain the C++ facilities for expressing recursion and iteration, but I do not go into technical
details or spend much time explaining how these concepts are useful
...
Many programmers lack experience with exceptions or
got their experience from languages (such as Java) where resource management and exception handling are not integrated
...
It goes into some detail
about strategy with a focus on the ‘‘Resource Acquisition Is Initialization’’ technique (RAII)
...
1
...
The chapters fall into three rough categories: classes, class hierarchies, and templates
...

Chapter 17 Construction, Cleanup, Copy, and Move shows how a programmer can define the
meaning of creation and initialization of objects of a class
...

Chapter 18 Operator Overloading presents the rules for giving meaning to operators for
user-defined types with an emphasis on conventional arithmetic and logical operators, such as +, ∗, and &
...
’’

6

Notes to the Reader

Chapter 1

Classes can be organized into hierarchies:
Chapter 20 Derived Classes presents the basic language facilities for building hierarchies out
of classes and the fundamental ways of using them
...

The C++ model for access control (public, protected, and private) is presented
...
It also
presents the notion of multiple inheritance, that is, a class having more than one
direct base class
...
We can use dynamic_cast to inquire whether an object of
a base class was defined as an object of a derived class and use the typeid to gain
minimal information from an object (such as the name of its class)
...
Class
templates, function templates, and template aliases are presented
...
The technique of lifting an abstract algorithm from a number of concrete
code examples is central, as is the notion of concepts specifying a generic algorithm’s requirements on its arguments
...

Chapter 26 Instantiation focuses on the rules for name binding
...

Chapter 28 Metaprogramming explores how templates can be used to generate programs
...

Chapter 29 A Matrix Design gives a longish example to show how language features can be
used in combination to solve a complex design problem: the design of an Ndimensional matrix with near-arbitrary element types
...
The presentation technique in Part III differs from that of Part II in that I don’t assume that
the reader knows the techniques described
...
1
...
In particular, they are meant to be
read in any order and can be used as a user-level manual for the library components:
Chapter 30 Standard-Library Overview gives an overview of the standard library, lists the
standard-library headers, and presents language support and diagnostics support,
such as exception and system_error
...


Section 1
...
4

Chapter 32
Chapter 33
Chapter 34

Chapter 35
Chapter 36
Chapter 37

Chapter 38
Chapter 39

Chapter 40
Chapter 41
Chapter 42

Chapter 43
Chapter 44

The Standard Library

7

STL Algorithms presents the algorithms from the STL, including find(), sort(),
and merge()
...

Memory and Resources presents utility components related to memory and
resource management, such as array, bitset, pair, tuple, unique_ptr, shared_ptr,
allocators, and the garbage collector interface
...

Strings documents the string library, including the character traits that are the
basis for the use of different character sets
...

I/O Streams documents the stream I/O library
...

Locales describes class locale and its various facets that provide support for the
handling of cultural differences in character sets, formatting of numeric values,
formatting of date and time, and more
...

Concurrency presents the C++ basic memory model and the facilities offered for
concurrent programming without locks
...

The C Standard Library documents the C standard library (including printf() and
clock()) as incorporated into the C++ standard library
...


1
...
5 Examples and References
This book emphasizes program organization rather than the design of algorithms
...
A trivial algorithm is typically better suited to
illustrate an aspect of the language definition or a point about program structure
...
Often, reimplementation with a
more suitable algorithm is an exercise
...

Textbook examples necessarily give a warped view of software development
...
I see no substitute for
writing realistically sized programs in order to get an impression of what programming and a

8

Notes to the Reader

Chapter 1

programming language are really like
...
These are the basic techniques from which every program is composed
...

The selection of examples reflects my background in compilers, foundation libraries, and simulations
...
Examples are simplified versions of what is found in real code
...
My ideal is the shortest and clearest example that
illustrates a design principle, a programming technique, a language construct, or a library feature
...
For purely language-technical
examples, I use variables named x and y, types called A and B, and functions called f() and g()
...
The language features presented and the detail in which
they are described roughly reflect my view of what is needed for effective use of C++
...
An
understanding of every language-technical detail of a language feature or library component is neither necessary nor sufficient for writing good programs
...
What is
needed is an understanding of design and programming techniques together with an appreciation of
application domains
...
The final arbiter of language and
standard-library rules is the ISO C++ standard [C++,2011]
...
3
...
5
...
1 (ISO C++ standard, §5
...
1)
...
g
...
g
...

To save a few trees and to simplify additions, the hundreds of exercises for this book have been
moved to the Web
...
stroustrup
...

The language and library used in this book are ‘‘pure C++’’ as defined by the C++ standard
[C++,2011]
...
The
major program fragments in this book were tried using several C++ implementations
...
However, I
see no point in mentioning which implementations failed to compile which examples
...
See Chapter 44 for suggestions on how to
cope with older C++ compilers and with code written for C compilers
...
For example, I prefer
{}-style initializers and using for type aliases
...
’’ However, being startled is often a good way to start reviewing material
...

Obviously, if you have to use a pre-C++11 compiler (say, because some of your customers have
not yet upgraded to the current standard), you have to refrain from using novel features
...

§44
...


Section 1
...
2 The Design of C++
The purpose of a programming language is to help express ideas in code
...
The first purpose ideally requires a language that is ‘‘close to the
machine’’ so that all important aspects of a machine are handled simply and efficiently in a way
that is reasonably obvious to the programmer
...
The second purpose ideally requires a language that is ‘‘close to the problem to be solved’’
so that the concepts of a solution can be expressed directly and concisely
...
Thus, C++ is based on the
idea of providing both
• direct mappings of built-in operations and types to hardware to provide efficient memory
use and efficient low-level operations, and
• affordable and flexible abstraction mechanisms to provide user-defined types with the same
notational support, range of uses, and performance as built-in types
...
Over the years, further application
of these simple ideals resulted in a far more general, efficient, and flexible set of facilities
...

The design of C++ has focused on programming techniques dealing with fundamental notions
such as memory, mutability, abstraction, resource management, expression of algorithms, error handling, and modularity
...

By defining libraries of classes, class hierarchies, and templates, you can write C++ programs at
a much higher level than the one presented in this book
...
4
...
For high-level applications programming to be effective and convenient, we need libraries
...
That’s true for every general-purpose
language
...

My standard introduction of C++ used to start:
• C++ is a general-purpose programming language with a bias toward systems programming
...
What has changed over the years is an increase in the importance, power, and
flexibility of C++’s abstraction mechanisms:
• C++ is a general-purpose programming language providing a direct and efficient model of
hardware combined with facilities for defining lightweight abstractions
...

By general-purpose programming language I mean a language designed to support a wide variety
of uses
...
No language is ideal for every application and every programmer,
but the ideal for C++ is to support the widest possible range of application areas well
...
In particular, the implementation of
software infrastructure (e
...
, device drivers, communications stacks, virtual machines, operating
systems, operations systems, programming environments, and foundation libraries) is mostly systems programming
...

Of course, you can also program in ways that completely hide hardware, use expensive abstractions (e
...
, every object on the free store and every operation a virtual function), use inelegant styles
(e
...
, overabstraction), or use essentially no abstractions (‘‘glorified assembly code’’)
...

The Design and Evolution of C++ book [Stroustrup,1994] (known as D&E) outlines the ideas
and design aims of C++ in greater detail, but two principles should be noted:
• Leave no room for a lower-level language below C++ (except for assembly code in rare
cases)
...

• What you don’t use you don’t pay for
...
Therefore, a language feature and
a fundamental abstraction must be designed not to waste a single byte or a single processor
cycle compared to equivalent alternatives
...

These are Draconian principles, but essential in some (but obviously not all) contexts
...
The STL is an example (§4
...
1, §4
...
5, Chapter 31, Chapter 32,
Chapter 33)
...


1
...
1 Programming Style
Languages features exist to provide support for programming styles
...

The general ideals for design and programming can be expressed simply:
• Express ideas directly in code
...

• Represent relationships among ideas directly in code
...

• Express simple ideas simply
...
A fundamental reason for that is that a language embodies a set of engineering tradeoffs
reflecting differing needs, tastes, and histories of various individuals and communities
...


Section 1
...
1

Programming Style

11

The C++ language features most directly support four programming styles:
• Procedural programming
• Data abstraction
• Object-oriented programming
• Generic programming
However, the emphasis is on the support of effective combinations of those
...
) solution to most nontrivial problems tends to be one
that combines aspects of these styles
...
For example, what I
refer to as a ‘‘programming style,’’ others call a ‘‘programming technique’’ or a ‘‘paradigm
...
I feel
uncomfortable with the word ‘‘paradigm’’ as pretentious and (from Kuhn’s original definition) having implied claims of exclusivity
...

• Procedural programming: This is programming focused on processing and the design of
suitable data structures
...
C++’s support comes in the form of the built-in types, operators, statements, functions, structs, unions, etc
...
Compared to C, C++ provides further support for procedural programming in the
form of many additional language constructs and a stricter, more flexible, and more supportive type system
...
C++ supports concrete and
abstract classes
...
The notion of an
abstract class provides direct support for complete data hiding
...
In addition to allowing the definition lattices of classes, C++
provides a variety of features for navigating class lattices and for simplifying the definition
of a class out of existing ones
...
3
...
2) and encapsulation (§20
...
5)
...
Here, ‘‘general’’ means that an algorithm can be designed to accept a
wide variety of types as long as they meet the algorithm’s requirements on its arguments
...
Templates provide (compiletime) parametric polymorphism
...
Thus, C++ could be (and has been) called class oriented
...

Focusing exclusively on one of these styles is a mistake: except for toy examples, doing so leads to
wasted development effort and suboptimal (inflexible, verbose, poorly performing, unmaintainable,
etc
...


12

Notes to the Reader

Chapter 1

I wince when someone characterizes C++ exclusively through one of these styles (e
...
, ‘‘C++ is
an object-oriented language’’) or uses a term (e
...
, ‘‘hybrid’’ or ‘‘mixed paradigm’’) to imply that a
more restrictive language would be preferable
...
The styles mentioned are not distinct alternatives: each contributes techniques to a more
expressive and effective style of programming, and C++ provides direct language support for their
use in combination
...

Even the earliest published account of C++ [Stroustrup,1982] presents examples that use these different styles in combination and presents language features aimed at supporting such combinations:
• Classes support all of the mentioned styles; all rely on the user representing ideas as userdefined types or objects of user-defined types
...

• Member functions, constructors, destructors, and user-defined assignment provide a clean
functional interface to objects as needed by data abstraction and object-oriented programming
...
More
general overloading had to wait until 1984 and uniform initialization until 2010
...
They are necessary for overloading
...

• Generic functions and parameterized types (generated from functions and classes using
macros) support generic programming
...

• Base and derived classes provide the foundation for object-oriented programming and some
forms of data abstraction
...

• Inlining made the use of these facilities affordable in systems programming and for building
run-time and space efficient libraries
...
Today’s C++ provides much better support for design and programming based on
lightweight abstraction, but the aim of elegant and efficient code was there from the very beginning
...

The fundamental object in C++ has identity; that is, it is located in a specific location in memory and can be distinguished from other objects with (potentially) the same value by comparing
addresses
...
4)
...
In C++11, this notion of rvalue
has been developed into a notion of a value that can be moved around cheaply (§3
...
2, §6
...
1,
§7
...
2)
...
This nicely complements the techniques and language features (e
...
, lambda expressions) developed primarily for
generic programming
...
g
...


Section 1
...
1

Programming Style

13

From the very earliest days, C++ programs and the design of C++ itself have been concerned
about resource management
...
2),
• perfect (no leaks are acceptable), and
• statically type-safe
...
Foundation and application libraries beyond the standard
provided many more examples, such as Matrix and Widget
...
This was soon backed with the ability to control copy by defining
assignment as well as copy constructors
...
3) in C++11 completes this line of thinking by allowing cheap movement of potentially
large objects from scope to scope (§3
...
2) and to simply control the lifetime of polymorphic or
shared objects (§5
...
1)
...
Any class that establishes and maintains an invariant relies on a subset of those features
...
2
...
For this reason, restricting language features with the intent of eliminating programmer errors is, at best, dangerous
...
Good design and the
absence of errors cannot be guaranteed merely by the presence or absence of specific language features
...

The notion of static types and compile-time type checking is central to effective use of C++
...
Following Simula, the design of user-defined types with interfaces that are checked at compile time is key to the
expressiveness of C++
...

C++ type-checking and data-hiding features rely on compile-time analysis of programs to prevent accidental corruption of data
...
They can, however, be used freely without incurring run-time or space overheads
...

C++’s static type system is flexible, and the use of simple user-defined types implies little, if
any overhead
...
A type-rich style of programming makes code more

14

Notes to the Reader

Chapter 1

readable, maintainable, and analyzable
...
C++ compilers and development tools support such type-based analysis [Stroustrup,2012]
...
However, my ideal is (and always was) complete type safety
...
’’ Note that Simula was both
type-safe and flexible
...
’’ However, the list of solid reasons against basing my work on type-safe
Algol68 [Woodward,1974] was long and painful
...
But it is an ideal that C++ programmers (especially library
builders) can strive for
...
Outside of low-level sections of code (hopefully
isolated by type-safe interfaces), code that interfaces to code obeying different language conventions (e
...
, an operating system call interface), and the implementations of fundamental abstractions
(e
...
, string and vector), there is now little need for type-unsafe code
...
2
...
The main reasons for relying on C were to build on a proven set of low-level language
facilities and to be part of a technical community
...
The continuing, more or less parallel evolution of C
and C++ has been a constant source of concern and requires constant attention [Stroustrup,2002]
...
In particular, there are differences in opinion as
to the value of compatibility, differences in opinion on what constitutes good programming, and
differences in opinion on what support is needed for good programming
...

One hundred percent C/C++ compatibility was never a goal for C++ because that would compromise type safety and the smooth integration of user-defined and built-in types
...
C++98 adopted many details from C89 (§44
...
1)
...
C’s facilities for low-level systems programming tasks are retained and enhanced; for
example, see inlining (§3
...
1
...
1
...
2
...
2
...
4, §12
...
6)
...
g
...

The definition of C++ has been revised to ensure that a construct that is both legal C and legal
C++ has the same meaning in both languages (§44
...

One of the original aims for C was to replace assembly coding for the most demanding systems
programming tasks
...
2
...
The difference between C and C++ is primarily in the degree of emphasis on types and structure
...
Through extensive use of the type system, C++ is even more
expressive without loss of performance
...
Programming in C encourages many techniques and tricks that are rendered unnecessary by C++ language features
...
3
...
However, good
C programs tend to be C++ programs
...
Experience with
any statically typed language will be a help when learning C++
...
2
...
C++ has no built-in high-level data types
and no high-level primitive operations
...
If a user wants such
a type, it can be defined in the language itself
...
A well-designed userdefined type differs from a built-in type only in the way it is defined, not in the way it is used
...
) provides many examples
of such types and their uses
...
Except for a few unfortunate and unimportant historical accidents, the C++ standard library is written in C++
...
This ensures that they can be used in large systems that typically consist of layer
upon layer of abstraction
...
For
example, constructs that would make it necessary to store ‘‘housekeeping information’’ in every
object were rejected, so if a user declares a structure consisting of two 16-bit quantities, that structure will fit into a 32-bit register
...
This
can be essential for embedded and high-performance applications
...
So, programmers of such applications don’t have to work with a low-level
(error-prone, impoverished, and unproductive) set of language features
...
Fortunately, C++ was never restricted
to UNIX; it simply used UNIX and C as a model for the relationships among language, libraries,
compilers, linkers, execution environments, etc
...
There are, however, good reasons for using C++ in environments that provide significantly more run-time support
...


16

Notes to the Reader

Chapter 1

Not every piece of code can be well structured, hardware-independent, easy to read, etc
...
It also possesses facilities for hiding
such code behind elegant and safe interfaces
...
C++’s emphasis on modularity, strongly typed interfaces, and flexibility pays off here
...

This book emphasizes techniques for providing general-purpose facilities, generally useful
types, libraries, etc
...
Furthermore, because all nontrivial programs consist of many semi-independent parts, the techniques for writing such parts serve programmers of all applications
...

This introduces library components and their underlying design concepts and implementation techniques
...

However, if the standard library provides a component that addresses a problem, it is almost always
better to use that component than to build your own
...
Over the
longer term, the standard component (possibly accessed through a convenient custom interface) is
likely to lower long-term maintenance, porting, tuning, and education costs
...
With C++,
this is not so
...
, is typically a
bit shorter than the equivalent C program not using these facilities
...

C++ supports systems programming
...
The idea of writing all software in a
single language is a fantasy
...
By that, I meant that a C++, C, assembler, or Fortran
function could call functions in the other languages without extra overhead or conversion of data
structures passed among them
...
The use of multiple processes and
multiple address spaces relied on (extralinguistic) operating system support
...
Initially, I relied on the UNIX Shell for that, but just about
any ‘‘scripting language’’ will do
...
C++ was designed to be part of large, concurrent, multilanguage systems
...
3

Learning C++

17

1
...
Fortunately, a programming language does not have to be
perfect to be a good tool for building great systems
...
What is perfect for one task is
often seriously flawed for another because perfection in one area implies specialization
...

Not everything can be expressed directly using the built-in features of a language
...
Language features exist to support a variety of programming styles and techniques
...

Writing programs is essential; understanding a programming language is not just an intellectual
exercise
...

In practical programming, there is little advantage in knowing the most obscure language features or using the largest number of features
...
Only in the context provided by techniques and by other features does the feature acquire
meaning and interest
...

No significant system is built exclusively in terms of the language features themselves
...
We use libraries to improve maintainability, portability, and performance
...
g
...
Many of the most fundamental programming concepts are represented in the standard
library
...
The standard library
is the repository of much hard-earned knowledge of how to use C++ well
...
This has surprised some who – correctly – point
out that C++ isn’t the smallest or cleanest language ever designed
...

The most important thing to do when learning C++ is to focus on fundamental concepts (such
as type safety, resource management, and invariants) and programming techniques (such as
resource management using scoped objects and the use of iterators in algorithms) and not get lost in
language-technical details
...
For this, an appreciation of programming and design techniques is far more
important than understanding all the details
...


18

Notes to the Reader

Chapter 1

C++ programming is based on strong static type checking, and most techniques aim at achieving a high level of abstraction and a direct representation of the programmer’s ideas
...
To gain the benefits of C++, programmers coming to it from a different language must
learn and internalize idiomatic C++ programming style and technique
...

Thoughtlessly applying techniques effective in one language to another typically leads to awkward, poorly performing, and hard-to-maintain code
...
’’ You can write in the style of Fortran, C, Lisp, Java,
etc
...
Every language can be a fertile source of ideas about how to write C++ programs
...
Over the basic type system of a language, only
Pyrrhic victories are possible
...
C++ is safer and more expressive, and it reduces the need to
focus on low-level techniques
...
Chapter 44 is
a guide for programmers going from C++ to C, say, to deal with legacy code
...

There are several independently developed implementations of C++
...
To help master all of this you
can find textbooks, manuals, and a bewildering variety of online resources
...
Each has its own
emphasis and bias, so use at least two
...
3
...
Imitate good writing
...

The main ideal for C++ programming – as for programming in most higher-level languages – is
to express concepts (ideas, notions, etc
...
We try to ensure that the
concepts we talk about, represent with boxes and arrows on our whiteboard, and find in our (nonprogramming) textbooks have direct and obvious counterparts in our programs:
[1] Represent ideas directly in code
...
g
...

[3] Represent independent ideas independently in code
...


Section 1
...
1

Programming in C++

19

More specifically:
[5] Prefer statically type-checked solutions (when applicable)
...
g
...

[7] Don’t overabstract (i
...
, don’t generalize, introduce class hierarchies, or parameterize
beyond obvious needs and experience)
...
3
...


1
...
2 Suggestions for C++ Programmers
By now, many people have been using C++ for a decade or two
...
Often, what an experienced C++ programmer has failed to notice over the
years is not the introduction of new features as such, but rather the changes in relationships
between features that make fundamental new programming techniques feasible
...
You find out only by reexamining the basics
...
If you already know the contents of a chapter, you can be
done in minutes
...
I learned a fair bit writing this book, and I suspect that hardly any C++ programmer knows
every feature and technique presented
...
Through its organization and examples,
this book offers such a perspective
...
4
...
2, §13
...
2
...

[2] Use constructor/destructor pairs to simplify resource management (RAII; §5
...
3)
...
2
...
2, §11
...
1)
...
4, §4
...
4, Chapter 32)
...
2
...

[6] Use exceptions, rather than error codes, to report errors that cannot be handled locally
(§2
...
3, §13
...

[7] Use move semantics to avoid copying large objects (§3
...
2, §17
...
2)
...
2
...

[9] Use shared_ptr to reference shared objects, that is, objects without a single owner that is
responsible for their destruction (§5
...
1)
...
2)
...
3
...
3
...


1
...
3 Suggestions for C Programmers
The better one knows C, the harder it seems to be to avoid writing C++ in C style, thereby losing
many of the potential benefits of C++
...


20

Notes to the Reader

Chapter 1

[1]

Don’t think of C++ as C with a few features added
...
To get really major advantages from C++ as compared to C, you need to
apply different design and implementation styles
...

[3] Use the C++ standard library as a teacher of new techniques and programming styles
...
g
...

[4] Macro substitution is almost never necessary in C++
...
5), constexpr (§2
...
3,
§10
...
4) to define manifest constants, inline (§12
...
5) to avoid
function-calling overhead, templates (§3
...
4
...
3
...

[5] Don’t declare a variable before you need it, and initialize it immediately
...
3), in for-statement initializers (§9
...
4
...

[6] Don’t use malloc()
...
2) does the same job better, and instead of
realloc(), try a vector (§3
...
2)
...
2
...
2, §11
...
1)
...
Their use limits the support you can get from the type system and can harm performance
...
If you must use an
explicit type conversion, try using one of the named casts (e
...
, static_cast; §11
...
2) for a
more precise statement of what you are trying to do
...
C++ standard-library strings (§4
...
2
...
4
...
In general, try not to build yourself what has
already been provided by the standard library
...
g
...

[10] Do not assume that something laboriously written in C style (avoiding C++ features such
as classes, templates, and exceptions) is more efficient than a shorter alternative (e
...
,
using standard-library facilities)
...

To obey C linkage conventions, a C++ function must be declared to have C linkage (§15
...
5)
...
3
...
Their aims are significantly different and so are many of their application domains
...
To use C++
well, you need to adopt programming and design techniques appropriate to C++, rather than trying
to write Java in C++
...


Section 1
...
4

Suggestions for Java Programmers

21

[2]

Use the C++ abstraction mechanisms (e
...
, classes and templates): don’t fall back to a C
style of programming out of a false feeling of familiarity
...

[4] Don’t immediately invent a unique base for all of your classes (an Object class)
...

[5] Minimize the use of reference and pointer variables: use local and member variables
(§3
...
1
...
2, §16
...
4, §17
...

[6] Remember: a variable is never implicitly a reference
...

[8] A function is not virtual by default
...

[9] Use abstract classes as interfaces to class hierarchies; avoid ‘‘brittle base classes,’’ that is,
base classes with data members
...

[11] Use a constructor to establish a class invariant (and throw an exception if it can’t)
...
g
...
Don’t imitate finally (doing so is more ad hoc and in the longer run far
more work than relying on destructors)
...
g
...
g
...

[14] Use freestanding functions (nonmember functions) to minimize coupling (e
...
, see the
standard algorithms), and use namespaces (§2
...
2, Chapter 14) to limit the scope of freestanding functions
...
5
...
1)
...

[17] C++ offers only the most minimal run-time reflection: dynamic_cast and typeid (Chapter
22)
...
g
...

Most of this advice applies equally to C# programmers
...
4 History
I invented C++, wrote its early definitions, and produced its first implementation
...

C++ was designed to provide Simula’s facilities for program organization [Dahl,1970]
[Dahl,1972] together with C’s efficiency and flexibility for systems programming [Kernighan,1978]
[Kernighan,1988]
...
The class concept (with derived classes and virtual functions) was borrowed from it
...


22

Notes to the Reader

Chapter 1

The evolution of C++ was always in the context of its use
...
In particular, my colleagues at
AT&T Bell Laboratories were essential for the growth of C++ during its first decade
...
Furthermore, it does not go into details
...
My two papers from the ACM History of Programming Languages conference and my
Design and Evolution of C++ book (known as ‘‘D&E’’) describe the design and evolution of C++
in detail and document influences from other programming languages
...
In my FAQ, I try to maintain a connection between the standard facilities and the people
who proposed and refined those facilities [Stroustrup,2010]
...


1
...
1 Timeline
The work that led to C++ started in the fall of 1979 under the name ‘‘C with Classes
...
The initial feature set included classes and derived
classes, public/private access control, constructors and destructors, and function declarations with argument checking
...

1984 ‘‘C with Classes’’ was renamed to C++
...

1985 First commercial release of C++ (October 14)
...

1985 The C++ Programming Language (‘‘TC++PL,’’ October 14) [Stroustrup,1986]
...

1991 The C++ Programming Language, Second Edition [Stroustrup,1991], presenting generic
programming using templates and error handling based on exceptions (including the
‘‘Resource Acquisition Is Initialization’’ general resource management idiom)
...
The standard
library added the STL framework of generic containers and algorithms
...

2002 Work on a revised standard, colloquially named C++0x, started
...
A C++ Technical Report
introduced new standard-library components, such as regular expressions, unordered containers (hash tables), and resource management pointers, which later became part of
C++0x
...


Section 1
...
1

Timeline

23

2009 C++0x was feature complete
...
The standard library added several components, including
threads, locks, and most of the components from the 2003 Technical Report
...

2012 The first complete C++11 implementations emerged
...

2013 The C++ Programming Language, Fourth Edition introduced C++11
...
As is not uncommon in large projects, we
were overly optimistic about the completion date
...
4
...
For that, I needed some event-driven simulations for which Simula would have been
ideal, except for performance considerations
...
The result of adding Simula-style
classes to C, ‘‘C with Classes,’’ was used for major projects in which its facilities for writing programs that use minimal time and space were severely tested
...
The first
use of C++ outside a research organization started in July 1983
...
The name signifies the evolutionary nature of the changes from C; ‘‘++’’ is the C increment operator
...
Connoisseurs
of C semantics find C++ inferior to ++C
...
For yet another interpretation of the name
C++, see the appendix of [Orwell,1949]
...
Its main purpose was to make writing good
programs easier and more pleasant for the individual programmer
...
There was
no ‘‘C++ project’’ either, or a ‘‘C++ design committee
...


1
...
2
...
I used
macros to provide primitive parameterization
...
Late that year, I was

24

Notes to the Reader

Chapter 1

able to present a set of language facilities supporting a coherent set of programming styles; see
§1
...
1
...

In the terminology of the time, ‘‘a constructor creates the execution environment for the member
functions and the destructor reverses that
...
If there were other languages at the time that supported multiple constructors capable of executing general code, I didn’t (and don’t) know of them
...

C++ was released commercially in October 1985
...
1
...
2
...
2
...
5, §16
...
9), function overloading (§12
...
7), operator
overloading (§3
...
1
...
2
...
3
...
Of these
features, support for run-time polymorphism in the form of virtual functions was by far the most
controversial
...
Systems programmers tended to view indirect function
calls with suspicion, and people acquainted with other languages supporting object-oriented programming had a hard time believing that virtual functions could be fast enough to be useful in systems code
...
The resistance to virtual functions may be related to a resistance to
the idea that you can get better systems through more regular structure of code supported by a programming language
...
My view was (and is) that
we need every bit of help we can get from languages and tools: the inherent complexity of the systems we are trying to build is always at the edge of what we can express
...
In the early years,
the feedback from Stu Feldman, Alexander Fraser, Steve Johnson, Brian Kernighan, Doug McIlroy,
and Dennis Ritchie was invaluable
...
The most important of those were templates [Stroustrup,1988] and exception handling
[Koenig,1990], which were considered experimental at the time the standards effort started
...

At the time, nobody knew how to simultaneously get all three, and to compete with C-style code
for demanding systems applications, I felt that I had to choose the first two properties
...
The design of exceptions focused on
multilevel propagation of exceptions, the passing of arbitrary information to an error handler, and
the integrations between exceptions and resource management by using local objects with destructors to represent and release resources (what I clumsily called ‘‘Resource Acquisition Is Initialization’’; §13
...

I generalized C++’s inheritance mechanisms to support multiple base classes [Stroustrup,1987a]
...
I
considered it far less important than templates or exceptions
...


Section 1
...
2
...
For example, I designed the complex [Stroustrup,1984], vector, stack, and (I/O) stream
[Stroustrup,1985] classes together with the operator overloading mechanisms
...
Jonathan’s
string and list classes were the first to see extensive use as part of a library
...
The task library described in [Stroustrup,1987b] was part of the first ‘‘C with Classes’’ program ever written in 1980
...
Unfortunately, we had to wait until 2011
(30 years!) to get concurrency support standardized and universally available (§1
...
4
...
3, Chapter 41)
...

C++ grew up in an environment with a multitude of established and experimental programming
languages (e
...
, Ada [Ichbiah,1979], Algol 68 [Woodward,1974], and ML [Paulson,1996])
...
However, the determining influences always came from
the applications I encountered
...


1
...
3 The 1998 Standard
The explosive growth of C++ use caused some changes
...
The result was a conscious effort to maintain contact
between implementers of C++ compilers and major users
...

AT&T Bell Labs made a major contribution to C++ and its wider community by allowing me to
share drafts of revised versions of the C++ reference manual with implementers and users
...
A less enlightened company
could have caused major problems of language fragmentation simply by doing nothing
...
Their names can be found in The Annotated C++ Reference Manual (‘‘the
ARM’’) [Ellis,1989]
...
In June 1991, this ANSI (American national) standardization of C++
became part of an ISO (international) standardization effort for C++ and named WG21
...
I served on these committees throughout
...
An initial draft standard for public review was produced in April 1995
...
A ‘‘bug
fix release’’ of this standard was issued in 2003, so you sometimes hear people refer to C++03, but
that is essentially the same language as C++98
...
4
...
1 Language Features
By the time the ANSI and ISO standards efforts started, most major language features were in place
and documented in the ARM [Ellis,1989]
...
The template mechanisms, in particular, benefited from much
detailed work
...
At the initiative of Dmitry Lenkov from Hewett-Packard, minimal facilities to use run-time type information (RTTI; Chapter 22) were introduced
...
I tried to get a facility
for optional conservative garbage collection accepted, but failed
...

Clearly, the 1998 language was far superior in features and in particular in the detail of specification to the 1989 language
...
In addition to the
inevitable minor mistakes, two major features were added that in retrospect should not have been:
• Exception specifications provide run-time enforcement of which exceptions a function is
allowed to throw
...
Exception specifications turned out to be worse than useless for improving readability, reliability, and performance
...
The 2011 standard introduced noexcept (§13
...
1
...

• It was always obvious that separate compilation of templates and their uses would be ideal
[Stroustrup,1994]
...
After a long debate in the committee, a compromise was
reached and something called export templates were specified as part of the 1998 standard
...
We are still looking for a solution
...
Thus, export solved the wrong problem
...
3) may help by providing precise specification of template requirements
...


1
...
3
...
4, §4
...
It was the work of Alex Stepanov (with Dave Musser, Meng Le, and others) based
on more than a decade’s work on generic programming
...
The STL has been massively influential
within the C++ community and beyond
...
I had failed to ship a sufficiently large foundation library with Release 1
...
0
...
4
...
2

The Standard Library

27

time the standards work started
...
g
...

The standard-library string (§4
...
The valarray library for numerical computation (§40
...
Jerry Schwarz transformed my streams library (§1
...
2
...
3, Chapter 38) using Andrew Koenig’s manipulator technique (§38
...
5
...
The
iostreams library was further refined during standardization, where the bulk of the work was done
by Jerry Schwarz, Nathan Myers, and Norihiro Kumagai
...
For example, there is no standard
GUI, database access library, or Web application library
...
The reasons for that are practical and commercial, rather than technical
...


1
...
4 The 2011 Standard
The current C++, C++11, known for years as C++0x, is the work of the members of WG21
...
These processes probably led to a better (and more rigorous) specification, but they also limited innovation
[Stroustrup,2007]
...
The second
ISO C++ standard (ISO/IEC 14882-2011) [C++,2011] was ratified by a 21-0 national vote in
August 2011
...
Consequently, serious work on
new language features did not start until 2002
...
In terms of pages of standards text, the language grew by
about 30% and the standard library by about 100%
...
Also, the work on a new C++ standard obviously had
to take great care not to compromise older code through incompatible changes
...

The overall aims for the C++11 effort were:
• Make C++ a better language for systems programming and library building
...

The aims are documented and detailed in [Stroustrup,2007]
...

This involved a memory model (§41
...
3),
which is primarily the work of Hans Boehm, Brian McKnight, and others
...
Pete Becker, Peter Dimov, Howard Hinnant, William Kempf, Anthony
Williams, and others did massive amounts of work on that
...
3
...
Concurrency is an
area where a complete and detailed listing of who did what and why would require a very long
paper
...


1
...
4
...
2
...
By ‘‘better’’ I mean easier to read, easier to write, more elegant, less error-prone, more maintainable, faster-running, consuming fewer resources, etc
...
3
...
6
...
6
...

• Deducing the type of an object from its initializer, auto: §2
...
2, §6
...
6
...

I first designed and implemented auto in 1983 but had to remove it because of C compatibility problems
...
2
...
4, §12
...
6; Gabriel Dos Reis and Bjarne Stroustrup [DosReis,2010]
...
4
...

• Inheriting constructors: §20
...
5
...

• Lambda expressions, a way of implicitly defining function objects at the point of their use in
an expression: §3
...
3, §11
...

• Move semantics, a way of transmitting information without copying: §3
...
2, §17
...
2;
Howard Hinnant
...
5
...
1; David Abrahams, Rani Sharoni, and Doug Gregor
...
2
...

• The range-for statement: §2
...
5, §9
...
1; Thorsten Ottosen and Bjarne Stroustrup
...
3
...
Alisdair Meredith, Chris Uzdavinis, and Ville
Voutilainen
...
In particular, a
way of defining a template by binding some arguments of another template: §3
...
5, §23
...

• Typed and scoped enumerations: enum class: §8
...
1; David E
...

• Universal and uniform initialization (including arbitrary-length initializer lists and protection against narrowing): §2
...
2, §3
...
1
...
3
...
3
...
3
...

• Variadic templates, a mechanism for passing an arbitrary number of arguments of arbitrary
types to a template: §3
...
4, §28
...


Section 1
...
4
...
The technical reports to the
committee [WG21] and my C++11 FAQ [Stroustrup,2010a] give many of the names
...
The reason my name appears so often is (I
hope) not vanity, but simply that I chose to work on what I consider important
...
Their major role is to flesh out the C++ feature set to better
support programming styles (§1
...
1)
...

Much work went into a proposal that did not make it into the standard
...
g
...
It was designed, specified, implemented, and tested, but by a large majority the committee
decided that the proposal was not yet ready
...
However, the committee decided against ‘‘concepts’’ on the grounds of complexity, difficulty of use, and compile-time performance [Stroustrup,2010b]
...
’’ This is
currently a field of active research and design [Sutton,2011] [Stroustrup,2012a]
...
4
...
2 Standard Library
The work on what became the C++11 standard library started with a standards committee technical
report (‘‘TR1’’)
...

As for language features, I’ll only list a few standard-library components with references to the
text and the names of the individuals most closely associated with them
...
2
...
Some components, such as unordered_map (hash tables), were ones we simply didn’t
manage to finish in time for the C++98 standard
...
Boost is a volunteer organization
created to provide useful library components based on the STL [Boost]
...
4
...

• The basic concurrency library components, such as thread, mutex, and lock: §5
...
2; Pete
Becker, Peter Dimov, Howard Hinnant, William Kempf, Anthony Williams, and more
...
3
...
4
...

• The garbage collection interface: §34
...

• A regular expression library, regexp: §5
...

• A random number library: §5
...
3, §40
...
It was about time
...

Several utility components were tried out in Boost:
• A pointer for simply and efficiently passing resources, unique_ptr: §5
...
1, §34
...
1; Howard
E
...
This was originally called move_ptr and is what auto_ptr should have been had
we known how to do so for C++98
...
2
...
3
...
A
successor to the C++98 counted_ptr proposal from Greg Colvin
...
4
...
5, §34
...
4
...
They credit a
long list of contributors, including Doug Gregor, David Abrahams, and Jeremy Siek
...
5
...
His acknowledgments list a veritable who’s who
of Boost (including Doug Gregor, John Maddock, Dave Abrahams, and Jaakko Jarvi)
...
5
...
He credits William
Kempf and others with contributions
...
4
...
You don’t usually see it
...

C++ is used by millions of programmers in essentially every application domain
...
This massive use is supported by
half a dozen independent implementations, many thousands of libraries, hundreds of textbooks, and
dozens of websites
...

Early applications tended to have a strong systems programming flavor
...
Many current ones (e
...
, Windows, Apple’s OS,
Linux, and most portable-device OSs) have key parts done in C++
...
I consider uncompromising low-level efficiency essential
for C++
...
In such code, predictability of performance
is at least as important as raw speed
...
C++
was designed so that every language feature is usable in code under severe time and space constraints (§1
...
4) [Stroustrup,1994,§4
...

Some of today’s most visible and widely used systems have their critical parts written in C++
...
Many other programming languages
and technologies depend critically on C++’s performance and reliability in their implementation
...
g
...
g
...
g
...
g
...
NET Web
services framework)
...

Most applications have sections of code that are critical for acceptable performance
...
For most code, maintainability, ease of extension, and ease of testing are key
...
Examples
are financial systems, telecommunications, device control, and military applications
...
S
...
e
...
Many
such applications are large and long-lived
...
Multimillion-line C++ programs are common
...
4
...
Thus, games has been
another major applications area for C++
...
g
...
g
...
g
...
g
...

C++ wasn’t specifically designed with numerical computation in mind
...
A major reason for this is that traditional numerical work must often be combined with graphics and with computations relying on
data structures that don’t fit into the traditional Fortran mold (e
...
, [Root,1995])
...

C++’s ability to be used effectively for applications that require work in a variety of application
areas is an important strength
...
Traditionally, such application
areas were considered distinct and were served by distinct technical communities using a variety of
programming languages
...
It is
designed so that C++ code can coexist with code written in other languages
...
Furthermore, no really major system is written 100% in a single language
...

Major applications are not written in just the raw language
...
There are many thousands of
C++ libraries, so keeping up with them all is impossible
...
5 Advice
Each chapter contains an ‘‘Advice’’ section with a set of concrete recommendations related to its
contents
...
A piece of advice
should be applied only where reasonable
...

I find rules of the form ‘‘never do this’’ unhelpful
...
Negative suggestions tend not to be phrased as absolute prohibitions
and I try to suggest alternatives
...
The ‘‘Advice’’ sections do not contain explanations
...

For starters, here are a few high-level recommendations derived from the sections on design,
learning, and history of C++:

32

Notes to the Reader

Chapter 1

[1]

Represent ideas (concepts) directly in code, for example, as a function, a class, or an enumeration; §1
...

[2] Aim for your code to be both elegant and efficient; §1
...

[3] Don’t overabstract; §1
...

[4] Focus design on the provision of elegant and efficient abstractions, possibly presented as
libraries; §1
...

[5] Represent relationships among ideas directly in code, for example, through parameterization or a class hierarchy; §1
...
1
...
2
...

[7] C++ is not just object-oriented; §1
...
1
...
2
...

[9] Prefer solutions that can be statically checked; §1
...
1
...
2
...
4
...
1
...
2
...

[12] Use libraries, especially the standard library, rather than trying to build everything from
scratch; §1
...
1
...
2
...

[14] Low-level code is not necessarily efficient; don’t avoid classes, templates, and standardlibrary components out of fear of performance problems; §1
...
4, §1
...
3
...
3
...

[16] C++ is not just C with a few extensions; §1
...
3
...
You are not going to get
it right the first time
...
6 References
[Austern,2003]

[Barron,1963]
[Barton,1994]

[Berg,1995]
[Boehm,2008]
[Boost]
[Budge,1992]

Matt Austern et al
...
Software – Practice & Experience
...

November 2003
...
W
...
: The main features of CPL
...
6 (2):
134
...
comjnl
...
org/content/6/2/134
...
pdf+html
...
J
...
R
...
Addison-Wesley
...
1994
...

William Berg, Marshall Cline, and Mike Girou: Lessons Learned from the
OS/400 OO Project
...
Vol
...
10
...

Hans-J
...
Adve: Foundations of the C++ concurrency
memory model
...

The Boost library collection
...
boost
...

Kent Budge, J
...
Perry, and A
...
Robinson: High-Performance Scientific
Computation Using C++
...
USENIX C++ Conference
...
August 1992
...
6

[C,1990]

[C,1999]
[C,2011]
[C++,1998]
[C++Math,2010]
[C++,2011]
[Campbell,1987]
[Coplien,1995]
[Cox,2007]
[Czarnecki,2000]

[Dahl,1970]
[Dahl,1972]
[Dean,2004]

[Dechev,2010]

[DosReis,2006]
[DosReis,2010]

[DosReis,2011]

[Ellis,1989]
[Freeman,1992]
[Friedl,1997]:

References

33

X3 Secretariat: Standard – The C Language
...
ISO Standard
ISO/IEC 9899-1990
...
Washington, DC
...
Standard – The C Language
...

ISO/IEC 9899
...
X3J11/90-013-2011
...

ISO/IEC 14882:1998
...
ISO/IEC 29124:2010
...

ISO/IEC 14882:2011
...
: The Design of a Multiprocessor Operating System
...
USENIX C++ Conference
...
November 1987
...
Coplien: Curiously Recurring Template Patterns
...

February 1995
...
January
2007
...
com/˜rsc/regexp/regexp1
...

K
...
Eisenecker: Generative Programming: Methods, Tools,
and Applications
...
Reading, Massachusetts
...
ISBN
0-201-30977-7
...
Dahl, B
...
Nygaard: SIMULA Common Base Language
...
Oslo, Norway
...

O-J
...
A
...
Hoare: Hierarchical Program Construction in Structured Programming
...
New York
...

J
...
Ghemawat: MapReduce: Simplified Data Processing on Large
Clusters
...
2004
...
Dechev, P
...
Stroustrup: Understanding and Effectively
Preventing the ABA Problem in Descriptor-based Lock-free Designs
...
May 2010
...

POPL06
...

Gabriel Dos Reis and Bjarne Stroustrup: General Constant Expressions for
System Programming Languages
...
The 25th ACM Symposium
On Applied Computing
...

Gabriel Dos Reis and Bjarne Stroustrup: A Principled, Complete, and Efficient Representation of C++
...

Vol
...
2011
...
Ellis and Bjarne Stroustrup: The Annotated C++ Reference
Manual
...
Reading, Mass
...
ISBN 0-201-51459-1
...
Prentice
Hall
...
1992
...

Jeffrey E
...
Friedl: Mastering Regular Expressions
...

Sebastopol, California
...
ISBN 978-1565922570
...
: Design Patterns: Elements of Reusable Object-Oriented
Software
...
Reading, Massachusetts
...
ISBN
0-201-63361-2
...
: Concepts: Linguistic Support for Generic Programming in C++
...

John L
...
Patterson: Computer Architecture, Fifth Edition: A Quantitative Approach
...
San Francisco, California
...
ISBN 978-0123838728
...
Ichbiah et al
...
SIGPLAN Notices
...
14, No
...
June 1979
...
Kamath, Ruth E
...
Smith: Reaping Benefits
with Object-Oriented Technology
...
Vol
...
5
...

Brian W
...
Ritchie: The C Programming Language
...
Englewood Cliffs, New Jersey
...

Brian W
...
Ritchie: The C Programming Language,
Second Edition
...
Englewood Cliffs, New Jersey
...
ISBN
0-13-110362-8
...
Knuth: The Art of Computer Programming
...

Reading, Massachusetts
...

Andrew Koenig and Bjarne Stroustrup: C++: As close to C as possible – but
no closer
...
Vol
...
7
...

A
...
Koenig and B
...

Proc USENIX C++ Conference
...

Joseph C
...
NASA/TM-2002-211716
...
Addison-Wesley
...

ISBN 978-0201183955
...
McKenney: Is Parallel Programming Hard, And, If So, What Can
You Do About It? kernel
...
Corvallis, Oregon
...

http://kernel
...
html
...
Regex
...
boost
...
2009
...
Secker and Warburg
...
1949
...
Paulson: ML for the Working Programmer
...
Cambridge
...
ISBN 0-521-56543-X
...
Pirkelbauer, Y
...
Stroustrup: Design and Evaluation of
C++ Open Multi-Methods
...
Elsevier
Journal
...
doi:10
...
scico
...
06
...

Martin Richards and Colin Whitby-Strevens: BCPL – The Language and Its
Compiler
...
Cambridge
...
ISBN
0-521-21965-5
...
root
...
ch
...
6

[Rozier,1988]
[Siek,2000]

[Solodkyy,2012]
[Stepanov,1994]
[Stewart,1998]
[Stroustrup,1982]

[Stroustrup,1984]

[Stroustrup,1985]
[Stroustrup,1986]
[Stroustrup,1987]
[Stroustrup,1987b]

[Stroustrup,1988]
[Stroustrup,1991]
[Stroustrup,1993]

[Stroustrup,1994]
[Stroustrup,1997]

[Stroustrup,2002]

[Stroustrup,2007]

References

35

Web address
...
Rozier et al
...
Computing Systems
...
1, No
...
Fall 1988
...
Siek and Andrew Lumsdaine: Concept checking: Binding parametric polymorphism in C++
...
First Workshop on C++ Template Programming
...
2000
...
Solodkyy, G
...
Stroustrup: Open and Efficient Type Switch
for C++
...
OOPSLA’12
...
HP
Labs Technical Report HPL-94-34 (R
...
1994
...
W
...
Basic Decompositions
...

Philadelphia, Pennsylvania
...

B
...

Sigplan Notices
...
The first public description of ‘‘C with
Classes
...
Stroustrup: Operator Overloading in C++
...
IFIP WG2
...

September 1984
...
Stroustrup: An Extensible I/O Facility for C++
...
Summer 1985
USENIX Conference
...
Stroustrup: The C++ Programming Language
...
Reading, Massachusetts
...
ISBN 0-201-12078-X
...
Stroustrup: Multiple Inheritance for C++
...
EUUG Spring Conference
...

B
...
Shopiro: A Set of C Classes for Co-Routine Style Programming
...
USENIX C++ Conference
...

November 1987
...
Stroustrup: Parameterized Types for C++
...
USENIX C++ Conference, Denver
...

B
...
Addison-Wesley
...
1991
...

B
...
Proc
...
ACM Sigplan Notices
...
1993
...
Stroustrup: The Design and Evolution of C++
...
Reading, Mass
...
ISBN 0-201-54330-3
...
Stroustrup: The C++ Programming Language, Third Edition
...
Reading, Massachusetts
...
ISBN 0-201-88954-4
...
2000
...

B
...
The C/C++ Users Journal
...
www
...
com/papers
...

B
...
ACM HOPL-III
...


36

Notes to the Reader

[Stroustrup,2008]

Chapter 1

B
...
Addison-Wesley
...
ISBN 0-321-54372-6
...
Stroustrup: The C++11 FAQ
...
stroustrup
...
html
...
Stroustrup: The C++0x ‘‘Remove Concepts’’ Decision
...
Dobb’s Journal
...

[Stroustrup,2012a] B
...
Sutton: A Concept Design for the STL
...
January 2012
...
Stroustrup: Software Development for Infrastructure
...
January
2012
...
1109/MC
...
353
...
Sutton and B
...
Proc
...

July 2011
...
Tanenbaum: Modern Operating Systems, Third Edition
...
Upper Saddle River, New Jersey
...
ISBN 0-13-600663-9
...
: Minimizing Dependencies within Generic Classes for
Faster and Smaller Programs
...
October 2009
...
0
...
Reading, Massachusetts
...
ISBN 0-201-48345-9
...
Research Version,
Tenth Edition
...
February
1985
...
Josuttis: C++ Templates: The Complete
Guide
...
2002
...

[Veldhuizen,1995]
Todd Veldhuizen: Expression Templates
...
June 1995
...
Veldhuizen: C++ Templates are Turing Complete
...
2003
...
ACM Transactions on Mathematical Software, Vol
...
1
...

[WG21]
ISO SC22/WG21 The C++ Programming Language Standards Committee:
Document Archive
...
open-std
...

[Williams,2012]
Anthony Williams: C++ Concurrency in Action – Practical Multithreading
...
ISBN 978-1933988771
...
Wilson and Paul Lu (editors): Parallel Programming Using C++
...
Cambridge, Mass
...
ISBN 0-262-73118-5
...
Addison-Wesley
...
1999
...

[Woodward,1974]
P
...
Woodward and S
...
Bond: Algol 68-R Users Guide
...
London
...


2
A Tour of C++: The Basics
The first thing we do, let’s
kill all the language lawyers
...
1 Introduction
The aim of this chapter and the next three is to give you an idea of what C++ is, without going into
a lot of details
...
These are the language facilities supporting the styles most often seen in C and sometimes called procedural programming
...
Chapter 4 and
Chapter 5 give examples of standard-library facilities
...
If not, please consider reading a textbook, such as Programming: Principles and Practice Using C++ [Stroustrup,2009], before continuing here
...
If you find this ‘‘lightning tour’’
confusing, skip to the more systematic presentation starting in Chapter 6
...
For example, loops are not
discussed in detail until Chapter 10, but they will be used in obvious ways long before that
...

As an analogy, think of a short sightseeing tour of a city, such as Copenhagen or New York
...
You do not know the city after such a
tour
...
To really know a city, you have to live in
it, often for years
...
After the tour, the
real exploration can begin
...
Consequently, it
does not identify language features as present in C, part of C++98, or new in C++11
...
4 and Chapter 44
...
2 The Basics
C++ is a compiled language
...
A
C++ program typically consists of many source code files (usually simply called source files)
...
When we talk about portability of C++ programs, we usually
mean portability of source code; that is, the source code can be successfully compiled and run on a
variety of systems
...
g
...
g
...
g
...
g
...
That is, the C++ standard library can be implemented in C++ itself (and is with very
minor uses of machine code for things such as thread context switching)
...

C++ is a statically typed language
...
g
...
The type of an object determines
the set of operations applicable to it
...
2
...
2
...
4)
...
Here, they indicate the start and end of the function
body
...
A comment is for
the human reader; the compiler ignores comments
...
The program starts
by executing that function
...
’’ If no value is returned, the system will receive a value indicating successful completion
...
Not every operating system and execution
environment make use of that return value: Linux/Unix-based environments often do, but Windows-based environments rarely do
...
Here is a program that writes Hello, World!:
#include
int main()
{
std::cout << "Hello, World!\n";
}

The line #include instructs the compiler to include the declarations of the standard
stream I/O facilities as found in iostream
...
The operator << (‘‘put to’’) writes its second argument onto its first
...
A string
literal is a sequence of characters surrounded by double quotes
...
’’ In this case, \n is the
newline character, so that the characters written are Hello, World! followed by a newline
...
4
...
I usually leave out the std:: when discussing standard features; §2
...
2 shows how to
make names from a namespace visible without explicit qualification
...
For example:
#include
using namespace std;
double square(double x)
{
return x∗x;
}

// make names from std visible without std:: (§2
...
2)
// square a double precision floating-point number

40

A Tour of C++: The Basics

Chapter 2

void print_square(double x)
{
cout << "the square of " << x << " is " << square(x) << "\n";
}
int main()
{
print_square(1
...
234 is 1
...


2
...
2 Types, Variables, and Arithmetic
Every name and every expression has a type that determines the operations that may be performed
on it
...

A declaration is a statement that introduces a name into the program
...

• An object is some memory that holds a value of some type
...

• A variable is a named object
...
For example:
bool
char
int
double

// Boolean, possible values are true and false
// character, for example, 'a', ' z', and '9'
// integer, for example, 1, 42, and 1066
// double-precision floating-point number, for example, 3
...
0

Each fundamental type corresponds directly to hardware facilities and has a fixed size that determines the range of values that can be stored in it:
bool:
char:
int:
double:

A char variable is of the natural size to hold a character on a given machine (typically an 8-bit
byte), and the sizes of other types are quoted in multiples of the size of a char
...
e
...

The arithmetic operators can be used for appropriate combinations of these types:

Section 2
...
2

x+y
+x
x−y
−x
x∗y
x/y
x%y

Types, Variables, and Arithmetic

41

// plus
// unar y plus
// minus
// unar y minus
// multiply
// divide
// remainder (modulus) for integers

So can the comparison operators:
x==y
x!=y
xx>y
x<=y
x>=y

// equal
// not equal
// less than
// greater than
// less than or equal
// greater than or equal

In assignments and in arithmetic operations, C++ performs all meaningful conversions (§10
...
3)
between the basic types so that they can be mixed freely:
void some_function()
{
double d = 2
...

C++ offers a variety of notations for expressing initialization, such as the
universal form based on curly-brace-delimited initializer lists:

=

used above, and a

double d1 = 2
...
3};
complex z = 1;
complex z2 {d1,d2};
complex z3 = {1,2};

// a complex number with double-precision floating-point scalars

vector v {1,2,3,4,5,6};

// a vector of ints

// the = is optional with {
...
3
...
2)
...
5):
int i1 = 7
...
2};
int i3 = {7
...
2
...
Don’t introduce a name until you have a suitable value for it
...
2
...
1)
...
2;
auto z = sqrt(y);

// a bool
// a char
// an int
// a double
// z has the type of whatever sqr t(y) returns

With auto, we use the = syntax because there is no type conversion involved that might cause problems (§6
...
6
...

We use auto where we don’t have a specific reason to mention the type explicitly
...

• We want to be explicit about a variable’s range or precision (e
...
, double rather than float)
...
This is especially important in
generic programming where the exact type of an object can be hard for the programmer to know
and the type names can be quite long (§4
...
1)
...
3), C++ offers more specific operations for modifying a variable:
x+=y
++x
x−=y
−−x
x∗=y
x/=y
x%=y

// x = x+y
// increment: x = x+1
// x = x-y
// decrement: x = x-1
// scaling: x = x*y
// scaling: x = x/y
// x = x%y

These operators are concise, convenient, and very frequently used
...
2
...
5):
• const: meaning roughly ‘‘I promise not to change this value’’ (§7
...
This is used primarily
to specify interfaces, so that data can be passed to functions without fear of it being modified
...

• constexpr: meaning roughly ‘‘to be evaluated at compile time’’ (§10
...
This is used primarily to specify constants, to allow placement of data in memory where it is unlikely to be corrupted, and for performance
...
4∗square(dmv);
constexpr double max2 = 1
...
4∗square(var);

// dmv is a named constant
// var is not a constant
// OK if square(17) is a constant expression
// error : var is not a constant expression
// OK, may be evaluated at run time

Section 2
...
3

double sum(const vector&);
vector v {1
...
4, 4
...
2
...
For example:
constexpr double square(double x) { return x∗x; }

To be

constexpr, a function must be rather simple: just a return-statement computing a value
...
We allow a constexpr function to be called with non-constant-expression argu-

ments in contexts that do not require constant expressions, so that we don’t have to define essentially the same function twice: once for constant expressions and once for variables
...
g
...
2
...
3), case labels (§2
...
4, §9
...
2), some template arguments (§25
...
In other cases, compile-time evaluation is important for performance
...
4)
...
2
...
For example,
here is a simple function that prompts the user and returns a Boolean indicating the response:
bool accept()
{
cout << "Do you want to proceed (y or n)?\n";
char answer = 0;
cin >> answer;

// write question

// read answer

if (answer == 'y') return true;
return false;
}

To match the << output operator (‘‘put to’’), the >> operator (‘‘get from’’) is used for input; cin is
the standard input stream
...
The \n character at the end
of the output string represents a newline (§2
...
1)
...
\n";
return false;
}
}

A switch-statement tests a value against a set of constants
...
If no default is provided, no
action is taken if the value doesn’t match any case constant
...
For example, we might like to give the user a few tries
to produce acceptable input:
bool accept3()
{
int tries = 1;
while (tries<4) {
cout << "Do you want to proceed (y or n)?\n";
char answer = 0;
cin >> answer;

// write question
// read answer

switch (answer) {
case 'y':
return true;
case 'n':
return false;
default:
cout << "Sorry, I don't understand that
...
\n";
return false;
}

The while-statement executes until its condition becomes false
...
2
...
’’ All arrays have

0

as their lower

Section 2
...
5

Pointers, Arrays, and Loops

45

bound, so v has six elements, v[0] to v[5]
...
2
...
A pointer variable can hold the address of an object of the appropriate type:
char∗ p = &v[3];
char x = ∗p;

// p points to v’s four th element
// *p is the object that p points to

In an expression, prefix unary ∗ means ‘‘contents of’’ and prefix unary & means ‘‘address of
...

}

This for-statement can be read as ‘‘set i to zero; while i is not 10, copy the ith element and increment
i
...
C++ also offers
a simpler for-statement, called a range-for-statement, for loops that traverse a sequence in the simplest way:
void print()
{
int v[] = {0,1,2,3,4,5,6,7,8,9};
for (auto x : v)
cout << x << '\n';

// for each x in v

for (auto x : {10,21,32,43,54,65})
cout << x << '\n';
//
...
’’ Note that we don’t have to specify an array bound when we initialize it
with a list
...
4
...

If we didn’t want to copy the values from v into the variable x, but rather just have x refer to an
element, we could write:

46

A Tour of C++: The Basics

Chapter 2

void increment()
{
int v[] = {0,1,2,3,4,5,6,7,8,9};
for (auto& x : v)
++x;
//
...
’’ A reference is similar to a pointer,
except that you don’t need to use a prefix ∗ to access the value referred to by the reference
...
When used in declarations, operators (such as &, ∗, and []) are called declarator operators:
T a[n];
T∗ p;
T& r;
T f(A);

// T[n]: array of n Ts (§7
...
2)
// T&: reference to T (§7
...
2
...
When
we don’t have an object to point to or if we need to represent the notion of ‘‘no object available’’
(e
...
, for an end of a list), we give the pointer the value nullptr (‘‘the null pointer’’)
...

The definition of count_x() assumes that the char∗ is a C-style string, that is, that the pointer
points to a zero-terminated array of char
...
2
...
However, using nullptr
eliminates potential confusion between integers (such as 0 or NULL) and pointers (such as nullptr)
...
3

User-Defined Types

47

2
...
2
...
2
...
2
...
C++’s set of built-in types and operations is
rich, but deliberately low-level
...
However, they don’t provide the programmer with high-level facilities to conveniently write advanced applications
...
The C++ abstraction mechanisms are primarily designed to let programmers design
and implement their own types, with suitable representations and operations, and for programmers
to simply and elegantly use such types
...
They are referred to as classes and enumerations
...
The rest of
this chapter presents the simplest and most fundamental facilities for that
...

Chapter 4 and Chapter 5 present an overview of the standard library, and since the standard library
mainly consists of user-defined types, they provide examples of what can be built using the language facilities and programming techniques presented in Chapter 2 and Chapter 3
...
3
...

A variable of type Vector can be defined like this:
Vector v;

However, by itself that is not of much use because v’s elem pointer doesn’t point to anything
...
For example, we can construct a Vector like this:
void vector_init(Vector& v, int s)
{
v
...
sz = s;
}

That is, v’s elem member gets a pointer produced by the new operator and v’s size member gets the
number of elements
...
2
...
7); that way, vector_init() can modify the vector passed to it
...
2)
...
elem[i];
// read into elements
double sum = 0;
for (int i=0; i!=s; ++i)
sum+=v
...

In particular, a user of Vector has to know every detail of Vector’s representation
...

Chapter 4 presents the standard-library vector, which contains many nice improvements, and Chapter 31 presents the complete vector in the context of other standard-library facilities
...

Don’t reinvent standard-library components, such as vector and string; use them
...
(dot) to access struct members through a name (and through a reference) and −> to
access struct members through a pointer
...
sz;
// access through name
int i2 = rv
...
3
...
However, a tighter connection between the representation and the
operations is needed for a user-defined type to have all the properties expected of a ‘‘real type
...
To do that we have
to distinguish between the interface to a type (to be used by all) and its implementation (which has
access to the otherwise inaccessible data)
...
A
class is defined to have a set of members, which can be data, function, or type members
...
For example:

Section 2
...
2

Classes

class Vector {
public:
Vector(int s) :elem{new double[s]}, sz{s} { }
double& operator[](int i) { return elem[i]; }
int size() { return sz; }
private:
double∗ elem; // pointer to the elements
int sz;
// the number of elements
};

49

// construct a Vector
// element access: subscripting

Given that, we can define a variable of our new type Vector:
Vector v(6);

// a Vector with 6 elements

We can illustrate a Vector object graphically:
Vector:
elem:
sz:

0:

1:

2:

3:

4:

5:

6

Basically, the Vector object is a ‘‘handle’’ containing a pointer to the elements (elem) plus the number of elements (sz)
...
2
...
3)
...
This is the basic technique for
handling varying amounts of information in C++: a fixed-size handle referring to a variable amount
of data ‘‘elsewhere’’ (e
...
, on the free store allocated by new; §11
...
How to design and use such
objects is the main topic of Chapter 3
...
The read_and_sum()
example from §2
...
1 simplifies to:
double read_and_sum(int s)
{
Vector v(s);
for (int i=0; i!=v
...
size(); ++i)
sum+=v[i];
return sum;

// make a vector of s elements
// read into elements

// take the sum of the elements

}

A ‘‘function’’ with the same name as its class is called a constructor, that is, a function used to construct objects of a class
...
3
...
Unlike an
ordinary function, a constructor is guaranteed to be used to initialize objects of its class
...


50

A Tour of C++: The Basics

Chapter 2

Vector(int) defines how objects of type Vector are constructed
...
That integer is used as the number of elements
...
Then, we initialize sz to s
...
It returns a reference
to the appropriate element (a double&)
...

Obviously, error handling is completely missing, but we’ll return to that in §2
...
3
...
2
...
2
shows how to use a destructor to elegantly do that
...
3
...
g
...
For example, Color::red is Color’s red
which is different from Traffic_light::red
...
They are used to make code
more readable and less error-prone than it would have been had the symbolic (and mnemonic) enumerator names not been used
...
Being separate types, enum classes help prevent accidental misuses of constants
...
4
...

By default, an enum class has only assignment, initialization, and comparisons (e
...
, == and <;
§2
...
2) defined
...
3
...
4
...


2
...
2
...
3, §3
...
2
...
4, Chapter 23)
...
The first and most important step is to distinguish between the interface to a part and
its implementation
...
A declaration specifies all that’s needed to use a function or a type
...
’’ For this
example, we might like for the representation of Vector to be ‘‘elsewhere’’ also, but we will deal
with that later (abstract types; §3
...
2)
...
algorithm as found in math textbook
...
However,
that makes no real difference: a library is simply some ‘‘other code we happen to use’’ written with
the same language facilities as we use
...
4
...
The definitions of those types and functions are in separate source files and compiled separately
...
Such separation can be used to minimize compilation times and to strictly enforce separation of logically distinct parts of a program (thus minimizing the chance of errors)
...
g
...

Typically, we place the declarations that specify the interface to a module in a file with a name
indicating its intended use
...
h:
class Vector {
public:
Vector(int s);
double& operator[](int i);
int size();
private:
double∗ elem;
// elem points to an array of sz doubles
int sz;
};

This declaration would be placed in a file
file, to access that interface
...
h,

and users will include that file, called a header

// user
...
h"
#include
using namespace std;

// get Vector’s interface
// get the the standard-librar y math function interface including sqrt()
// make std members visible (§2
...
2)

Section 2
...
1

Separate Compilation

double sqrt_sum(Vector& v)
{
double sum = 0;
for (int i=0; i!=v
...
h file providing its interface:


...
cpp:
#include "Vector
...
cpp and Vector
...
h,
but the two files are otherwise independent and can be separately compiled
...
h:
Vector

user
...
h"
use Vector

interface
Vector
...
h"
define Vector

Strictly speaking, using separate compilation isn’t a language issue; it is an issue of how best to
take advantage of a particular language implementation
...
The best approach is to maximize modularity, represent that modularity logically through
language features, and then exploit the modularity physically through files for effective separate
compilation (Chapter 14, Chapter 15)
...
4
...
2
...
3
...
4),
C++ offers namespaces (Chapter 14) as a mechanism for expressing that some declarations belong
together and that their names shouldn’t clash with other names
...
2
...
1, §18
...
4):
namespace My_code {
class complex { /*
...

int main();
}
int My_code::main()
{
complex z {1,2};
auto z2 = sqrt(z);
std::cout << '{' << z2
...
imag() << "}\n";
//
...
1
...
The precaution is wise, because the standard
library does provide support for complex arithmetic (§3
...
1
...
4)
...
g
...
The ‘‘real main()’’ is defined in the global namespace,
that is, not local to a defined namespace, class, or function
...
2
...
They
simplify the composition of a program out of separately developed parts
...
4
...
However, C++ provides a few features to
help
...
Instead of painstakingly building up our applications
from the built-in types (e
...
, char, int, and double) and statements (e
...
, if, while, and for), we build
more types that are appropriate for our applications (e
...
, string, map, and regex) and algorithms
(e
...
, sort(), find_if(), and draw_all())
...
g
...
4
...
The majority of C++ constructs are
dedicated to the design and implementation of elegant and efficient abstractions (e
...
, user-defined
types and algorithms using them)
...
As programs grow, and especially when libraries are used extensively,
standards for handling errors become important
...
4
...
1 Exceptions
Consider again the Vector example
...
3
...

• The user of Vector cannot consistently detect the problem (if the user could, the out-of-range
access wouldn’t happen in the first place)
...
The user can then take appropriate action
...
To do that, the implementation will unwind the
function call stack as needed to get back to the context of that caller (§13
...
1)
...

try { // exceptions here are handled by the handler defined below
v[v
...
handle range error
...

}

We put code for which we are interested in handling exceptions into a try-block
...
size()] will fail
...
The out_of_range type is defined in the standard library and is in fact used by some
standard-library container access functions
...
See Chapter 13 for further discussion, details, and examples
...
4
...
2 Invariants
The use of exceptions to signal out-of-range access is an example of a function checking its argument and refusing to act because a basic assumption, a precondition, didn’t hold
...
Whenever we define a
function, we should consider what its preconditions are and if feasible test them (see §12
...
4)
...
In particular, we did say ‘‘elem points to
an array of sz doubles’’ but we only said that in a comment
...
It is the job of a constructor
to establish the invariant for its class (so that the member functions can rely on it) and for the member functions to make sure that the invariant holds when they exit
...
It properly initialized the Vector members, but it failed to check
that the arguments passed to it made sense
...

Here is a more appropriate definition:
Vector::Vector(int s)
{
if (s<0) throw length_error{};
elem = new double[s];
sz = s;
}

I use the standard-library exception length_error to report a non-positive number of elements
because some standard-library operations use that exception to report problems of this kind
...
We can now write:
void test()
{
try {
Vector v(−27);
}
catch (std::length_error) {
// handle negative size
}
catch (std::bad_alloc) {
// handle memory exhaustion
}
}

You can define your own classes to be used as exceptions and have them carry arbitrary information
from a point where an error is detected to a point where it can be handled (§13
...

Often, a function has no way of completing its assigned task after an exception is thrown
...
5
...
1)
...
4
...
2

Invariants

57

The notion of invariants is central to the design of classes, and preconditions serve a similar role
in the design of functions
...

The notion of invariants underlies C++’s notions of resource management supported by constructors (§2
...
2) and destructors (§3
...
1
...
2)
...
4, §16
...
1, and §17
...


2
...
3
...
If an error can be found at compile time, it is usually
preferable to do so
...
However, we can also perform simple checks on other properties that are known at compile time and report failures as compiler error messages
...
We call such statements of expectations assertions
...
2
...
4)
...
458;

// km/s

void f(double speed)
{
const double local_max = 160
...
0/(60*60) km/s

static_assert(speedstatic_assert(local_max
// error : speed must be a constant
// OK

//
...

The most important uses of static_assert come when we make assertions about types used as
parameters in generic programming (§5
...
2, §24
...

For runtime-checked assertions, see §13
...


2
...

Those are the parts of C++ that underlie all programming techniques and styles supported by C++
...


58

A Tour of C++: The Basics

2
...
1
...
3
...

Focus on programming techniques, not on language features; §2
...


Chapter 2

3
A Tour of C++: Abstraction Mechanisms
Don’t Panic!
– Douglas Adams







Introduction
Classes
Concrete Types; Abstract Types; Virtual Functions; Class Hierarchies
Copy and Move
Copying Containers; Moving Containers; Resource Management; Suppressing Operations
Templates
Parameterized Types; Function Templates; Function Objects; Variadic Templates; Aliases
Advice

3
...
It informally presents ways of defining and using new types
(user-defined types)
...
Templates are
introduced as a mechanism for parameterizing types and algorithms with (other) types and algorithms
...
These are the language facilities supporting
the programming styles known as object-oriented programming and generic programming
...

The assumption is that you have programmed before
...
Even if you have programmed before, the language you used or the applications you
wrote may be very different from the style of C++ presented here
...


60

A Tour of C++: Abstraction Mechanisms

Chapter 3

As in Chapter 2, this tour presents C++ as an integrated whole, rather than as a layer cake
...
Such historical information can be found in §1
...


3
...
A class is a user-defined type provided to represent a concept in the code of a program
...
, we try to represent it as a class in the program so that the idea is there in the code,
rather than just in our head, in a design document, or in some comments
...
In particular, classes are often what libraries offer
...
By ‘‘better,’’ I mean more correct,
easier to maintain, more efficient, more elegant, easier to use, easier to read, and easier to reason
about
...
The needs and tastes of programmers vary immensely
...
Here, we will just consider the basic support for three important kinds of
classes:
• Concrete classes (§3
...
1)
• Abstract classes (§3
...
2)
• Classes in class hierarchies (§3
...
4)
An astounding number of useful classes turn out to be of these three kinds
...


3
...
1 Concrete Types
The basic idea of concrete classes is that they behave ‘‘just like built-in types
...
Similarly, a vector and a string are much
like built-in arrays, except that they are better behaved (§4
...
3
...
4
...

The defining characteristic of a concrete type is that its representation is part of its definition
...
That allows implementations to be optimally efficient in time and space
...
4
...
g
...
3
...
3)
...
3
...
Therefore, if the representation changes in any significant way, a
user must recompile
...
2
...
For types that don’t change often, and where local variables provide much-needed clarity
and efficiency, this is acceptable and often ideal
...
That’s the way vector and string are implemented; they can
be considered resource handles with carefully crafted interfaces
...
2
...
1 An Arithmetic Type
The ‘‘classical user-defined arithmetic type’’ is complex:
class complex {
double re, im; // representation: two doubles
public:
complex(double r, double i) :re{r}, im{i} {}
complex(double r) :re{r}, im{0} {}
complex() :re{0}, im{0} {}

// construct complex from two scalars
// construct complex from one scalar
// default complex: {0,0}

double real() const { return re; }
void real(double d) { re=d; }
double imag() const { return im; }
void imag(double d) { im=d; }
complex& operator+=(complex z) { re+=z
...
im; return ∗this; }

// add to re and im
// and return the result

complex& operator−=(complex z) { re−=z
...
im; return ∗this; }
complex& operator∗=(complex);
complex& operator/=(complex);

// defined out-of-class somewhere
// defined out-of-class somewhere

};

This is a slightly simplified version of the standard-library complex (§40
...
The class definition
itself contains only the operations requiring access to the representation
...
For practical reasons, it has to be compatible with what Fortran provided 50
years ago, and we need a conventional set of operators
...
This implies that simple operations must be inlined
...
Functions defined in a class are inlined by default
...

A constructor that can be invoked without an argument is called a default constructor
...
By defining a default constructor you eliminate the possibility of uninitialized variables of that type
...

Many useful operations do not require direct access to the representation of complex, so they
can be defined separately from the class definition:

62

A Tour of C++: Abstraction Mechanisms

complex operator+(complex a, complex b) { return a+=b; }
complex operator−(complex a, complex b) { return a−=b; }
complex operator−(complex a) { return {−a
...
imag()}; }
complex operator∗(complex a, complex b) { return a∗=b; }
complex operator/(complex a, complex b) { return a/=b; }

Chapter 3

// unar y minus

Here, I use the fact that an argument passed by value is copied, so that I can modify an argument
without affecting the caller’s copy, and use the result as the return value
...
real()==b
...
imag()==b
...


Class complex can be used like this:
void f(complex z)
{
complex a {2
...
3,0
...
3
complex b {1/a};
complex c {a+z∗complex{1,2
...

if (c != b)
c = −(b/a)+2∗b;
}

The compiler converts operators involving complex numbers into appropriate function calls
...

User-defined operators (‘‘overloaded operators’’) should be used cautiously and conventionally
...
Also, it is not possible to change
the meaning of an operator for built-in types, so you can’t redefine + to subtract ints
...
2
...
2 A Container
A container is an object holding a collection of elements, so we call Vector a container because it is
the type of objects that are containers
...
3
...
4
...
2), provides rangechecked access (§2
...
3
...
However, it
does have a fatal flaw: it allocates elements using new but never deallocates them
...
5), it is not

Section 3
...
1
...
In some environments you can’t use a collector, and sometimes you prefer more precise control of destruction
(§13
...
4) for logical or performance reasons
...
Vector’s constructor allocates some memory on the free store (also
called the heap or dynamic store) using the new operator
...
This is all done without intervention by users of Vector
...
For example:
void fct(int n)
{
Vector v(n);
//
...

{
Vector v2(2∗n);
//
...

} // v2 is destroyed here
//
...

} // v is destroyed here

obeys the same rules for naming, scope, allocation, lifetime, etc
...
For details on how to control the lifetime of an object, see §6
...
This Vector
has been simplified by leaving out error handling; see §2
...
3
...
In particular, it
is the basis for most C++ general resource management techniques (§5
...
3)
...
The destructor deallocates the elements
...
The technique of acquiring resources in a
constructor and releasing them in a destructor, known as Resource Acquisition Is Initialization or
RAII, allows us to eliminate ‘‘naked new operations,’’ that is, to avoid allocations in general code
and keep them buried inside the implementation of well-behaved abstractions
...
Avoiding naked new and naked delete makes code far less
error-prone and far easier to keep free of resource leaks (§5
...


3
...
1
...
We can handle that by creating a Vector with an appropriate number of elements and
then assigning to them, but typically other ways are more elegant
...

• push_back(): Add a new element at the end (at the back of) the sequence
...

void push_back(double);
//
...
For example:
Vector read(istream& is)
{
Vector v;
for (double d; is>>d;)
v
...
Until that happens, each number read is added to the Vector so that at the end, v’s size is the number of elements read
...
The implementation of push_back() is discussed in §13
...
4
...
The way to provide Vector with
a move constructor, so that returning a potentially huge amount of data from read() is cheap, is
explained in §3
...
2
...
2
...
3

Initializing Containers

65

The std::initializer_list used to define the initializer-list constructor is a standard-library type
known to the compiler: when we use a {}-list, such as {1,2,3,4}, the compiler will create an object of
type initializer_list to give to the program
...
23, 3
...
7, 8};
Vector’s

// v1 has 5 elements
// v2 has 4 elements

initializer-list constructor might be defined like this:

Vector::Vector(std::initializer_list lst)
// initialize with a list
:elem{new double[lst
...
size()}
{
copy(lst
...
end(),elem);
// copy from lst into elem
}

3
...
2 Abstract Types
Types such as complex and Vector are called concrete types because their representation is part of
their definition
...
In contrast, an abstract type is a type that
completely insulates a user from implementation details
...
Since we don’t know anything about
the representation of an abstract type (not even its size), we must allocate objects on the free store
(§3
...
1
...
2) and access them through references or pointers (§2
...
5, §7
...
7)
...
2
...
1)
// destructor (§3
...
1
...
The word virtual means ‘‘may be
redefined later in a class derived from this one
...
A class derived from Container provides an implementation for the Container interface
...
Thus, it is not possible to define an object that is just a
Container; a Container can only serve as the interface to a class that implements its operator[]() and
size() functions
...

This Container can be used like this:
void use(Container& c)
{
const int sz = c
...
It
uses size() and [] without any idea of exactly which type provides their implementation
...
3
...

As is common for abstract classes, Container does not have a constructor
...
On the other hand, Container does have a destructor and that destructor
is virtual
...
2
...

A container that implements the functions required by the interface defined by the abstract class
Container could use the concrete class Vector:
class Vector_container : public Container { // Vector_container implements Container
Vector v;
public:
Vector_container(int s) : v(s) { }
// Vector of s elements
˜Vector_container() {}
double& operator[](int i) { return v[i]; }
int size() const { return v
...
’’ Class Vector_container is said to
be derived from class Container, and class Container is said to be a base of class Vector_container
...
The derived class is said to inherit members from its base class, so the use of base and
derived classes is commonly referred to as inheritance
...
3
...
The destructor (˜Vector_container()) overrides the base class destructor
(˜Container())
...

For a function like use(Container&) to use a Container in complete ignorance of implementation
details, some other function will have to make an object on which it can operate
...
For example:
class List_container : public Container { // List_container implements Container
std::list ld;
// (standard-librar y) list of doubles (§4
...
2)
public:
List_container() { }
// empty List
List_container(initializer_list il) : ld{il} { }
˜List_container() {}

Section 3
...
2

Abstract Types

67

double& operator[](int i);
int size() const { return ld
...
Usually, I would not implement a container with a subscript operation using a list, because performance of list subscripting is atrocious
compared to vector subscripting
...

A function can create a List_container and have use() use it:
void h()
{
List_container lc = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
use(lc);
}

The point is that use(Container&) has no idea if its argument is a Vector_container, a List_container,
or some other kind of container; it doesn’t need to know
...
It knows
only the interface defined by Container
...

The flip side of this flexibility is that objects must be manipulated through pointers or references
(§3
...
4)
...
2
...
size();
for (int i=0; i!=sz; ++i)
cout << c[i] << '\n';
}

How is the call c[i] in use() resolved to the right operator[]()? When h() calls use(), List_container’s
operator[]() must be called
...
To
achieve this resolution, a Container object must contain information to allow it to select the right
function to call at run time
...
That table is usually

68

A Tour of C++: Abstraction Mechanisms

Chapter 3

called the virtual function table or simply the vtbl
...
This can be represented graphically like this:
vtbl:
Vector_container:
Vector_container::operator[]()
v
Vector_container::size()
Vector_container::˜Vector_container()

List_container:

vtbl:
List_container::operator[]()

ld

List_container::size()
List_container::˜List_container()

The functions in the vtbl allow the object to be used correctly even when the size of the object and
the layout of its data are unknown to the caller
...
This virtual call mechanism can be made almost as efficient as the ‘‘normal function call’’
mechanism (within 25%)
...


3
...
4 Class Hierarchies
The Container example is a very simple example of a class hierarchy
...
g
...
We use class hierarchies to represent concepts that have hierarchical relationships, such as ‘‘A fire engine is a kind of a truck
which is a kind of a vehicle’’ and ‘‘A smiley face is a kind of a circle which is a kind of a shape
...
As a semirealistic classic example, let’s consider shapes on a screen:
Shape

Circle

Triangle

Smiley

The arrows represent inheritance relationships
...
To represent that simple diagram in code, we must first specify a class that defines the general properties of all shapes:

Section 3
...
4

Class Hierarchies

class Shape {
public:
virtual Point center() const =0;
virtual void move(Point to) =0;

69

// pure virtual

virtual void draw() const = 0;
virtual void rotate(int angle) = 0;

// draw on current "Canvas"

virtual ˜Shape() {}
//
...
Given this definition, we can
write general functions manipulating vectors of pointers to shapes:
void rotate_all(vector& v, int angle) // rotate v’s elements by angle degrees
{
for (auto p : v)
p−>rotate(angle);
}

To define a particular shape, we must say that it is a
(including its virtual functions):
class Circle : public Shape {
public:
Circle(Point p, int rr);

Shape

and specify its particular properties

// constructor

Point center() const { return x; }
void move(Point to) { x=to; }
void draw() const;
void rotate(int) {}
private:
Point x; // center
int r;
// radius
};

// nice simple algorithm

So far, the

Shape and Circle example provides
Vector_container example, but we can build further:

nothing new compared to the

class Smiley : public Circle { // use the circle as the base for a face
public:
Smiley(Point p, int r) : Circle{p,r}, mouth{nullptr} { }
˜Smiley()
{
delete mouth;
for (auto p : eyes) delete p;
}

Container

and

70

A Tour of C++: Abstraction Mechanisms

Chapter 3

void move(Point to);
void draw() const;
void rotate(int);
void add_eye(Shape∗ s) { eyes
...

private:
vector eyes;
Shape∗ mouth;
};

// usually two eyes

The push_back() member function adds its argument to the vector (here, eyes), increasing that
vector’s size by one
...
Shape’s destructor is virtual and Smiley’s destructor overrides it
...
In particular, it may be deleted through a pointer to
a base class
...

That destructor then implicitly invokes the destructors of its bases and members
...

We can add data members, operations, or both as we define a new class by derivation
...
See Chapter
21
...
That is, the base class acts as an interface for the derived class
...
Such classes are often abstract classes
...
Smiley’s uses of Circle’s constructor and of Circle::draw()
are examples
...

Concrete classes – especially classes with small representations – are much like built-in types: we
define them as local variables, access them using their names, copy them around, etc
...
2
...
For example, consider a function that reads data describing
shapes from an input stream and constructs the appropriate Shape objects:
enum class Kind { circle, triangle, smiley };
Shape∗ read_shape(istream& is) // read shape descriptions from input stream is
{
//
...

switch (k) {
case Kind::circle:
// read circle data {Point,int} into p and r
return new Circle{p,r};
case Kind::triangle:
// read triangle data {Point,Point,Point} into p1, p2, and p3
return new Triangle{p1,p2,p3};
case Kind::smiley:
// read smiley data {Point,int,Shape,Shape,Shape} into p, r, e1 ,e2, and m
Smiley∗ ps = new Smiley{p,r};
ps−>add_eye(e1);
ps−>add_eye(e2);
ps−>set_mouth(m);
return ps;
}
}

A program may use that shape reader like this:
void user()
{
std::vector v;
while (cin)
v
...
The user()
code can be compiled once and later used for new Shapes added to the program
...
This is done
with the delete operator and relies critically on Shape’s virtual destructor
...
This is crucial because a derived
class may have acquired all kinds of resources (such as file handles, locks, and output streams) that
need to be released
...

Experienced programmers will notice that I left open two obvious opportunities for mistakes:
• A user might fail to delete the pointer returned by read_shape()
...

In that sense, functions returning a pointer to an object allocated on the free store are dangerous
...
2
...


// §5
...
1

}
void user()
{
vector> v;
while (cin)
v
...

For the unique_ptr version of user() to work, we need versions of draw_all() and rotate_all() that
accept vector>s
...
4
...


3
...
This is true for objects of user-defined types as well as for builtin types
...
For example,
using complex from §3
...
1
...

}

// copy initialization
// copy assignment

Now z1, z2, and z3 have the same value because both the assignment and the initialization copied
both members
...
For
simple concrete types, memberwise copy is often exactly the right semantics for copy
...


Section 3
...
1

Copying Containers

73

3
...
1 Copying Containers
When a class is a resource handle, that is, it is responsible for an object accessed through a pointer,
the default memberwise copy is typically a disaster
...
4
...
2)
...
6)
...

Copying of an object of a class is defined by two members: a copy constructor and a copy
assignment:
class Vector {
private:
double∗ elem; // elem points to an array of sz doubles
int sz;
public:
Vector(int s);
// constructor: establish invariant, acquire resources
˜Vector() { delete[] elem; }
// destructor: release resources
Vector(const Vector& a);
Vector& operator=(const Vector& a);

// copy constructor
// copy assignment

double& operator[](int i);
const double& operator[](int i) const;
int size() const;
};

A suitable definition of a copy constructor for Vector allocates the space for the required number of
elements and then copies the elements into it, so that after a copy each Vector has its own copy of
the elements:

74

A Tour of C++: Abstraction Mechanisms

Vector::Vector(const Vector& a)
:elem{new double[sz]},
sz{a
...
elem[i];
}

Chapter 3

// copy constructor
// allocate space for elements

// copy elements

The result of the v2=v1 example can now be presented as:
v1:

v2:

4

2

4

3

Of course, we need a copy assignment in addition to the copy constructor:
Vector& Vector::operator=(const Vector& a)
{
double∗ p = new double[a
...
sz; ++i)
p[i] = a
...
sz;
return ∗this;
}

// copy assignment

The name this is predefined in a member function and points to the object for which the member
function is called
...


3
...
2 Moving Containers
We can control copying by defining a copy constructor and a copy assignment, but copying can be
costly for large containers
...
size()!=b
...
size());
for (int i=0; i!=a
...
3
...
We might use this + like this:

res

75

and into some place

void f(const Vector& x, const Vector& y, const Vector& z)
{
Vector r;
//
...

}

That would be copying a Vector at least twice (one for each use of the + operator)
...
The most embarrassing part is that res in
operator+() is never used again after the copy
...
Fortunately, we can
state that intent:
class Vector {
//
...
This means that r=x+y+z will involve no copying of Vectors
...

As is typical, Vector’s move constructor is trivial to define:
Vector::Vector(Vector&& a)
:elem{a
...
sz}
{
a
...
sz = 0;
}

The && means ‘‘rvalue reference’’ and is a reference to which we can bind an rvalue (§6
...
1)
...
’’ So an rvalue is – to a first approximation – a value
that you can’t assign to, such as an integer returned by a function call, and an rvalue reference is a
reference to something that nobody else can assign to
...

A move constructor does not take a const argument: after all, a move constructor is supposed to
remove the value from its argument
...

A move operation is applied when an rvalue reference is used as an initializer or as the righthand side of an assignment
...
Typically, we should also allow assignment to a moved-from object (§17
...
6
...

Where the programmer knows that a value will not be used again, but the compiler can’t be
expected to be smart enough to figure that out, the programmer can be specific:
Vector f()
{
Vector x(1000);
Vector y(1000);
Vector z(1000);
//
...

return z;
};

// we get a copy
// we get a move
// we get a move

The standard-library function move() returns an rvalue reference to its argument
...


y:

0

1000

1

2


...


3
...
3 Resource Management
By defining constructors, copy operations, move operations, and a destructor, a programmer can
provide complete control of the lifetime of a contained resource (such as the elements of a container)
...
That way, objects that we cannot or would not want to copy out of a scope can be
simply and cheaply moved out instead
...
3
...
We can’t copy the former and don’t want to
copy the latter
...
push_back(move(t));
//
...


// run hear tbeat concurrently (on its own thread)
// move t into my_threads

Section 3
...
3

Resource Management

77

Vector vec(n);
for (int i=0; i ...
In fact, the standard-library ‘‘smart pointers,’’ such as unique_ptr, are themselves resource
handles (§5
...
1)
...
4
...

In very much the same way as new and delete disappear from application code, we can make
pointers disappear into resource handles
...
In particular, we can achieve strong resource safety; that is, we can
eliminate resource leaks for a general notion of a resource
...


3
...
4 Suppressing Operations
Using the default copy or move for a class in a hierarchy is typically a disaster: given only a pointer
to a base, we simply don’t know what members the derived class has (§3
...
2), so we can’t know
how to copy them
...

};

Now an attempt to copy a Shape will be caught by the compiler
...
2
...

In this particular case, if you forgot to delete a copy or move operation, no harm is done
...
Furthermore, the generation of copy operations is deprecated in this case (§44
...
3)
...
2
...

A base class in a class hierarchy is just one example of an object we wouldn’t want to copy
...
2, §17
...
2)
...
6
...


78

A Tour of C++: Abstraction Mechanisms

Chapter 3

3
...
A vector is a general
concept, independent of the notion of a floating-point number
...
A template is a class or a function that we parameterize with a set of types or values
...


3
...
1 Parameterized Types
We can generalize our vector-of-doubles type to a vector-of-anything type by making it a
and replacing the specific type double with a parameter
...
copy and move operations
...
It is C++’s version of the mathematical ‘‘for all T’’ or more precisely ‘‘for all types T
...
4
...
It is not (as in C++98) necessary to place a space between the two >s
...
size(); ++i)
cout << vs[i] << '\n';
}

// Vector of some strings

To support the range-for loop for our Vector, we must define suitable begin() and end() functions:
template
T∗ begin(Vector& x)
{
return &x[0];
// pointer to first element
}
template
T∗ end(Vector& x)
{
return x
...
size(); // pointer to one-past-last element
}

Given those, we can write:
void f2(const Vector& vs) // Vector of some strings
{
for (auto& s : vs)
cout << s << '\n';
}

Similarly, we can define lists, vectors, maps (that is, associative arrays), etc
...
4,
§23
...

Templates are a compile-time mechanism, so their use incurs no run-time overhead compared to
‘‘handwritten code’’ (§23
...
2)
...
4
...
In
particular, they are extensively used for parameterization of both types and algorithms in the standard library (§4
...
5, §4
...
5)
...
0);
// the sum of a vector of ints (add doubles)
double dd = sum(ld,0
...
0,0
...
Note how the types of the template arguments for sum are deduced from the function
arguments
...

This sum() is a simplified version of the standard-library accumulate() (§40
...


3
...
3 Function Objects
One particularly useful kind of template is the function object (sometimes called a functor), which
is used to define objects that can be called like functions
...

We can define named variables of type Less_than for some argument type:
Less_than lti {42};
// lti(i) will compare i to 42 using < (i<42)
Less_than lts {"Backus"}; // lts(s) will compare s to "Backus" using < (s<"Backus")

We can call such an object, just as we call a function:
void fct(int n, const string & s)
{
bool b1 = lti(n);
// true if n<42
bool b2 = lts(s);
// true if s<"Backus"
//
...
4
...
For example, we can count the
occurrences of values for which a predicate returns true:
template
int count(const C& c, P pred)
{
int cnt = 0;
for (const auto& x : c)
if (pred(x))
++cnt;
return cnt;
}

A predicate is something that we can invoke to return true or false
...
The beauty of these
function objects is that they carry the value to be compared against with them
...
Also, for a simple function object like Less_than inlining is simple,
so that a call of Less_than is far more efficient than an indirect function call
...

Function objects used to specify the meaning of key operations of a general algorithm (such as
Less_than for count()) are often referred to as policy objects
...
That could be seen as inconvenient
...
4)
...
The [&] is a capture list specifying that local names used
(such as x) will be passed by reference
...
Had we wanted to give the generated object a copy of x, we could have said so: [=x]
...

Using lambdas can be convenient and terse, but also obscure
...

In §3
...
4, we noticed the annoyance of having to write many functions to perform operations on
elements of vectors of pointers and unique_ptrs, such as draw_all() and rotate_all()
...

First, we need a function that applies an operation to each object pointed to by the elements of a
container of pointers:
template
void for_all(C& c, Oper op)
// assume that C is a container of pointers
{
for (auto& x : c)
op(∗x);
// pass op() a reference to each element pointed to
}

Now, we can write a version of user() from §3
...
4 without writing a set of _all functions:
void user()
{
vector> v;
while (cin)
v
...
draw(); });
for_all(v,[](Shape& s){ s
...
In particular, those for_all() calls would still work if I changed v
to a vector
...
4
...
Such a
template is called a variadic template
...
Tail>
void f(T head, Tail
...
); // try again with tail
}
void f() { }

// do nothing

The key to implementing a variadic template is to note that when you pass a list of arguments to it,

Section 3
...
4

Variadic Templates

83

you can separate the first argument from the rest
...
The ellipsis,
...
Eventually, of course, tail will become empty and we need a separate
function to deal with that
...
2,"hello");
cout << "\nsecond: "
f(0
...
2,"hello"), which will call f(2
...
What might the call g(head) do? Obviously, in a real program it will do whatever we wanted
done to each argument
...
2 hello
second: 0
...

The strength of variadic templates (sometimes just called variadics) is that they can accept any
arguments you care to give them
...
For details, see §28
...
For examples, see §34
...
4
...


3
...
5 Aliases
Surprisingly often, it is useful to introduce a synonym for a type or a template (§6
...
For example,
the standard header contains a definition of the alias size_t, maybe:
using size_t = unsigned int;

The actual type named size_t is implementation-dependent, so in another implementation size_t
may be an unsigned long
...

It is very common for a parameterized type to provide an alias for types related to their template
arguments
...

};

In fact, every standard-library container provides value_type as the name of its value type (§31
...
1)
...
For
example:
template
using Element_type = typename C::value_type;
template
void algo(Container& c)
{
Vector> vec; // keep results here
//
...
For example:
template
class Map {
//
...
6
...
5 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]

Express ideas directly in code; §3
...

Define classes to represent application concepts directly in code; §3
...

Use concrete classes to represent simple concepts and performance-critical components;
§3
...
1
...
2
...
2
...
2
...
2
...
2
...

Use class hierarchies to represent concepts with inherent hierarchical structure; §3
...
4
...
5

[8]
[9]
[10]
[11]
[12]
[13]
[14]
[15]

Advice

85

When designing a class hierarchy, distinguish between implementation inheritance and interface inheritance; §3
...
4
...
3
...
3
...

Provide strong resource safety; that is, never leak anything that you think of as a resource;
§3
...
3
...
4
...

Use function templates to represent general algorithms; §3
...
2
...
4
...

Use type and template aliases to provide a uniform notation for types that may vary among
similar types or among implementations; §3
...
5
...
1 Libraries
No significant program is written in just a bare programming language
...
These then form the basis for further work
...

Continuing from Chapters 2 and 3, this chapter and the next give a quick tour of key standardlibrary facilities
...
If not, please consider reading a
textbook, such as Programming: Principles and Practice Using C++ [Stroustrup,2009], before
continuing
...
If you find this ‘‘lightning tour’’
confusing, you might skip to the more systematic and bottom-up language presentation starting in
Chapter 6
...


88

A Tour of C++: Containers and Algorithms

Chapter 4

I very briefly present useful standard-library types, such as string, ostream, vector, map (this
chapter), unique_ptr, thread, regex, and complex (Chapter 5), as well as the most common ways of
using them
...
As in Chapter
2 and Chapter 3, you are strongly encouraged not to be distracted or discouraged by an incomplete
understanding of details
...

The specification of the standard library is almost two thirds of the ISO C++ standard
...
Much though have gone into its design, more still into
its implementations, and much effort will go into its maintenance and extension
...
In addition to the standard-library components, most implementations offer ‘‘graphical user
interface’’ systems (GUIs), Web interfaces, database interfaces, etc
...
Here, I do not describe such systems and libraries
...
Naturally, a programmer is encouraged to
explore the more extensive facilities available on most systems
...
1
...
g
...
3
...

• Strings and I/O streams (with support for international character sets and localization); see
Chapter 36, Chapter 38, and Chapter 39
...

• A framework of containers (such as vector and map) and algorithms (such as find(), sort(),
and merge()); see §4
...
5, Chapters 31-33
...

• Support for numerical computation (such as standard mathematical functions, complex
numbers, vectors with arithmetic operations, and random number generators); see §3
...
1
...

• Support for regular expression matching; see §5
...

• Support for concurrent programming, including threads and locks; see §5
...

The concurrency support is foundational so that users can add support for new models of
concurrency as libraries
...
g
...
4
...
2
...
4),
STL-style generic programming (e
...
, pair; §5
...
3, §34
...
4
...
g
...
4
...
2)
...
g
...
2
...
3)
and an interface to garbage collectors (§34
...

• Special-purpose containers, such as array (§34
...
1), bitset (§34
...
2), and tuple (§34
...
4
...


Section 4
...
1

Standard-Library Overview

89

The main criteria for including a class in the library were that:
• it could be helpful to almost every C++ programmer (both novices and experts),
• it could be provided in a general form that did not add significant overhead compared to a
simpler version of the same facility, and
• that simple uses should be easy to learn (relative to the inherent complexity of their task)
...


4
...
2 The Standard-library Headers and Namespace
Every standard-library facility is provided through some standard header
...

The standard library is defined in a namespace (§2
...
2, §14
...
1) called
library facilities, the std:: prefix can be used:

std
...
Neither will I always
#include the necessary headers explicitly
...
4
...
5
...
2) and make the names
they declare accessible
...

However, in this book, I use the standard library almost exclusively and it is good to know what it
offers
...
Nor do I #include the
appropriate headers in every example
...

Here is a selection of standard-library headers, all supplying declarations in namespace std:
Selected Standard Library Headers (continues)









copy(), find(), sort()
array
duration, time_point
sqrt(), pow()
complex, sqrt(), pow()
fstream, ifstream, ofstream
future, promise
istream, ostream, cin, cout

§32
...
2
...
2
§40
...
4
§38
...
1
§5
...
5
§38
...
25
§iso
...
3
...
20
...
2
§iso
...
8
§iso
...
8
§iso
...
9
...
30
...
27
...
4
...
2
...
7
Chapter 37
Chapter 36
§31
...
3
§38
...
2
§5
...
1
§31
...
3
...
5
§31
...
23
...
4
§iso
...
6
§iso
...
5
§iso
...
8
§iso
...
3
§iso
...
4
...
27
...
30
...
23
...
4
§iso
...
1
§iso
...
3
...
2 for more information
...
2 Strings
The standard library provides a string type to complement the string literals
...
For example:

string

type pro-

string compose(const string& name, const string& domain)
{
return name + '@' + domain;
}
auto addr = compose("dmr","bell−labs
...
com
...
You can concatenate a string, a string literal, a C-style string, or a character to a
string
...
3
...

In many applications, the most common form of concatenation is adding something to the end
of a string
...
For example:
void m2(string& s1, string& s2)
{
s1 = s1 + '\n'; // append newline
s2 += '\n';
// append newline
}

The two ways of adding to the end of a string are semantically equivalent, but I prefer the latter
because it is more explicit about what it does, more concise, and possibly more efficient
...
In addition to = and +=, subscripting (using []) and substring operations are
supported
...
Among other useful features, it
provides the ability to manipulate substrings
...
2

Strings

91

string name = "Niels Stroustrup";
void m3()
{
string s = name
...
replace(0,5,"nicholas");
name[0] = toupper(name[0]);
}

// s = "Stroustrup"
// name becomes "nicholas Stroustrup"
// name becomes "Nicholas Stroustrup"

The substr() operation returns a string that is a copy of the substring indicated by its arguments
...
Since indexing starts from 0, s gets the value Stroustrup
...
In this case, the substring starting at 0
with length 5 is Niels; it is replaced by nicholas
...
Thus, the final value of name is Nicholas Stroustrup
...

Naturally, strings can be compared against each other and against string literals
...

}
//
...
The most common techniques for implementing
example (§19
...


4
...

The input operations are typed and extensible to handle user-defined types
...

Other forms of user interaction, such as graphical I/O, are handled through libraries that are not
part of the ISO standard and therefore not described here
...
3
...
Further, it is easy to define output of a
user-defined type (§4
...
3)
...

By default, values written to cout are converted to a sequence of characters
...

Equivalently, we could write:
void g()
{
int i {10};
cout << i;
}

Output of different types can be combined in the obvious way:
void h(int i)
{
cout << "the value of i is ";
cout << i;
cout << '\n';
}

For h(10), the output will be:
the value of i is 10

People soon tire of repeating the name of the output stream when outputting several related items
...
For example:
void h2(int i)
{
cout << "the value of i is " << i << '\n';
}

This h2() produces the same output as h()
...
Note that a character is output as
a character rather than as a numerical value
...


Section 4
...
2

Input

93

4
...
2 Input
The standard library offers istreams for input
...

The operator >> (‘‘get from’’) is used as an input operator; cin is the standard input stream
...
For example:
void f()
{
int i;
cin >> i;
double d;
cin >> d;

// read an integer into i

// read a double-precision floating-point number into d

}

This reads a number, such as 1234, from the standard input into the integer variable i and a floatingpoint number, such as 12
...

Often, we want to read a sequence of characters
...
For example:
void hello()
{
cout << "Please enter your name\n";
string str;
cin >> str;
cout << "Hello, " << str << "!\n";
}

If you type in Eric the response is:
Hello, Eric!

By default, a whitespace character (§7
...
2), such as a space, terminates the read, so if you enter Eric
pretending to be the ill-fated king of York, the response is still:

Bloodaxe

Hello, Eric!

You can read a whole line (including the terminating newline character) using the getline() function
...

The standard strings have the nice property of expanding to hold what you put in them; you
don’t have to precalculate a maximum size
...


4
...
3 I/O of User-Defined Types
In addition to the I/O of built-in types and standard strings, the iostream library allows programmers
to define I/O for their own types
...
name << "\", " << e
...
See §38
...
2 for details
...
Note: formatted with { " " , and }
{
char c, c2;
if (is>>c && c=='{' && is>>c2 && c2=='"') { // star t with a { "
string name;
// the default value of a string is the empty string: ""
while (is
...
setf(ios_base::failbit);
return is;

// register the failure in the stream

}

An input operation returns a reference to its

istream

which can be used to test if the operation

Section 4
...
3

I/O of User-Defined Types

95

succeeded
...
get(c) does not, so that this Entry-input operator
ignores (skips) whitespace outside the name string, but not within it
...
4
...
See §5
...


4
...

Reading characters into a string and printing out the string is a simple example
...
Providing suitable containers for
a given task and supporting them with useful fundamental operations are important steps in the
construction of any program
...
This is the kind of program for which different approaches appear ‘‘simple and
obvious’’ to people of different backgrounds
...
3
...
Here, we deliberately ignore many real-world complexities, such as the
fact that many phone numbers do not have a simple representation as a 32-bit int
...
4
...
A vector is a sequence of elements of a given
type
...
2
...
4 give an idea of the implementation of vector and §13
...
4 provide an exhaustive discussion
...
size(); ++i)
cout << book[i] << '\n';
}

As usual, indexing starts at 0 so that book[0] holds the entry for David Hume
...

The elements of a vector constitute a range, so we can use a range-for loop (§2
...
5):
void print_book(const vector& book)
{
for (const auto& x : book)
// for "auto" see §2
...
2
cout << x << '\n';
}

When we define a vector, we give it an initial size (initial number of elements):
vector v1 = {1, 2, 3, 4};
vector v2;
vector v3(23);
vector v4(32,9
...
9

An explicit size is enclosed in ordinary parentheses, for example, (23), and by default the elements
are initialized to the element type’s default value (e
...
, nullptr for pointers and 0 for numbers)
...
g
...
9 for the 32 elements of v4)
...
One of the most useful operations on a vector is push_back(),
which adds a new element at the end of a vector, increasing its size by one
...
push_back(e);
}

This reads Entrys from the standard input into phone_book until either the end-of-input (e
...
, the
end of a file) is reached or the input operation encounters a format error
...

A vector can be copied in assignments and initializations
...
4
...
3
...
Thus, after the initialization
of book2, book2 and phone_book hold separate copies of every Entry in the phone book
...
Where copying is undesirable, references or pointers (§7
...
7) or move operations (§3
...
2,
§17
...
2) should be used
...
4
...
1 Elements
Like all standard-library containers, vector is a container of elements of some type T, that is, a
vector
...
When you insert a new element, its value is copied
into the container
...
The element is not a reference or a pointer to some object
containing 7
...
For people who care about
memory sizes and run-time performance this is critical
...
4
...
2 Range Checking
The standard-library vector does not guarantee range checking (§31
...
2)
...
size()]
...

}

// book
...
This is
undesirable, and out-of-range errors are a common problem
...
3
...
1
T& operator[](int i)
{ return vector::at(i); }
const T& operator[](int i) const
{ return vector::at(i); }

// range check

// range check const objects; §3
...
1
...
The at() operation is a vector subscript operation that throws an exception of type
out_of_range if its argument is out of the vector’s range (§2
...
3
...
2
...

Vec

98

A Tour of C++: Containers and Algorithms

Chapter 4

For Vec, an out-of-range access will throw an exception that the user can catch
...
size()] = {"Joe",999999};
//
...
4
...
1, Chapter 13)
...
One way to minimize surprises from uncaught exceptions is to use a main()
with a try-block as its body
...
) {
cerr << "unknown exception thrown\n";
}

This provides default exception handlers so that if we fail to catch some exception, an error message is printed on the standard error-diagnostic output stream cerr (§38
...

Some implementations save you the bother of defining Vec (or equivalent) by providing a rangechecked version of vector (e
...
, as a compiler option)
...
4
...
Insertion and deletion of phone book entries could be common, so a list could be appropriate for representing a simple phone book
...
4
...
Instead, we might search the list looking for an element with a given value
...
5:
int get_number(const string& s)
{
for (const auto& x : phone_book)
if (x
...
number;
return 0; // use 0 to represent "number not found"
}

The search for s starts at the beginning of the list and proceeds until s is found or the end of
phone_book is reached
...
For example, we may want to delete it or
insert a new entry before it
...
Every standard-library container provides the functions begin() and end(), which return an iterator to the first and to one-past-the-last
element, respectively (§4
...
1
...
Using iterators explicitly, we can – less elegantly – write the
get_number() function like this:
int get_number(const string& s)
{
for (auto p = phone_book
...
end(); ++p)
if (p−>name==s)
return p−>number;
return 0; // use 0 to represent "number not found"
}

In fact, this is roughly the way the terser and less error-prone range-for loop is implemented by the
compiler
...
m
...
insert(p,ee);
// add ee before the element referred to by p
phone_book
...
3
...

These list examples could be written identically using vector and (surprisingly, unless you
understand machine architecture) perform better with a small vector than with a small list
...
Unless
you have a reason not to, use a vector
...
g
...
g
...


100

A Tour of C++: Containers and Algorithms

Chapter 4

4
...
3 map
Writing code to look up a name in a list of (name,number) pairs is quite tedious
...
The standard library offers a search tree (a redblack tree) called map:
map:

links
4

links
key:
value:

links
links

In other contexts, a map is known as an associative array or a dictionary
...

The standard-library map (§31
...
3) is a container of pairs of values optimized for lookup
...
4
...
4
...
For example:
int get_number(const string& s)
{
return phone_book[s];
}

In other words, subscripting a map is essentially the lookup we called get_number()
...
The default value for an integer
type is 0; the value I just happened to choose represents an invalid telephone number
...
4
...
1)
...
4
...
That’s pretty
good
...
However, in many cases, we can do better by using a hashed
lookup rather than comparison using an ordering function, such as <
...
4
...
4
...
4)
...


If necessary, you

4
...
5 Container Overview
The standard library provides some of the most general and useful container types to allow the programmer to select a container that best serves the needs of an application:
Standard Container Summary
vector
list
forward_list
deque
set
multiset
map
multimap
unordered_map
unordered_multimap
unordered_set
unordered_multiset

A variable-size vector (§31
...
4
...
4
...
2)
A set (§31
...
3)
A set in which a value can occur many times (§31
...
3)
An associative array (§31
...
3)
A map in which a key can occur many times (§31
...
3)
A map using a hashed lookup (§31
...
3
...
4
...
2)
A set using a hashed lookup (§31
...
3
...
4
...
2)

The unordered containers are optimized for lookup with a key (often a string); in other words, they
are implemented using hash tables
...
4
...
(§4
...
2, §30
...
In addition, the standard
library provides container adaptors queue (§31
...
2), stack (§31
...
1), deque (§31
...
5
...
The standard library also provides more specialized container-like
types, such as a fixed-size array array (§34
...
1) and bitset (§34
...
2)
...
Furthermore, the meanings of the operations are equivalent for the various containers
...
For example:
• begin() and end() give iterators to the first and one-beyond-the-last elements, respectively
...

• size() returns the number of elements
...
The range-checked vector, Vector
(§2
...
2, §2
...
3
...
The uniformity of container interfaces also allows us to
specify algorithms independently of individual container types
...
For example, subscripting and traversing a vector is cheap and easy
...
Please note that a vector is usually more efficient than a list for short sequences of small
elements (even for insert() and erase())
...


4
...
To use one, we need operations for basic access such as adding and removing elements (as is provided for list and vector)
...
We sort them, print them, extract subsets,
remove elements, search for objects, etc
...
For
example, the following sorts a vector and places a copy of each unique vector element on a list:
bool operator<(const Entry& x, const Entry& y)
// less than
{
return x
...
name;
// order Entrys by their names
}
void f(vector& vec, list& lst)
{
sort(vec
...
end());
unique_copy(vec
...
end(),lst
...
They are expressed in terms of sequences of
elements
...
5

Algorithms

iterators:

begin()

103

end()

elements:
In the example, sort() sorts the sequence defined by the pair of iterators vec
...
end() –
which just happens to be all the elements of a vector
...
If more than one element is written, the elements following that initial element will be overwritten
...

If we wanted to place the unique elements in a new container, we could have written:
list f(vector& vec)
{
list res;
sort(vec
...
end());
unique_copy(vec
...
end(),back_inserter(res)); // append to res
return res;
}

A back_inserter() adds elements at the end of a container, extending the container to make room for
them (§33
...
2)
...
5
...
The standard-library list has
a move constructor (§3
...
2, §17
...
2) that makes returning res by value efficient (even for lists of
thousands of elements)
...
begin(),vec
...
5
...


4
...
1 Use of Iterators
When you first encounter a container, a few iterators referring to useful elements can be obtained;
begin() and end() are the best examples of this
...
For
example, the standard algorithm find looks for a value in a sequence and returns an iterator to the
element found:
bool has_c(const string& s, char c)
{
auto p = find(s
...
end(),c);
if (p!=s
...
’’ An equivalent, shorter, definition of has_c() is:

104

A Tour of C++: Containers and Algorithms

Chapter 4

bool has_c(const string& s, char c)
// does s contain the character c?
{
return find(s
...
end(),c)!=s
...
We can return the set of occurrences as a vector of string iterators
...
3
...
Assuming that we would like to
modify the locations found, we pass a non-const string:
vector find_all(string& s, char c)
{
vector res;
for (auto p = s
...
end(); ++p)
if (∗p==c)
res
...
We could test
find_all() like this:
void test()
{
string m {"Mary had a little lamb"};
for (auto p : find_all(m,'a'))
if (∗p!='a')
cerr << "a bug!\n";
}

That call of find_all() could be graphically represented like this:
find_all(m,’a’):

m:

M a

r

y

h a d

a

l

i

t

t

l

e

l

a m b

Iterators and standard algorithms work equivalently on every standard container for which their use
makes sense
...
begin(); p!=c
...
push_back(p);
return res;
}

// find all occurrences of v in c

Section 4
...
1

Use of Iterators

105

The typename is needed to inform the compiler that C’s iterator is supposed to be a type and not a
value of some type, say, the integer 7
...
4
...
begin(); p!=c
...
push_back(p);
return res;
}

We can now write:
void test()
{
string m {"Mary had a little lamb"};
for (auto p : find_all(m,'a'))
if (∗p!='a')
cerr << "string bug!\n";

// p is a string::iterator

list ld {1
...
2, 3
...
1};
for (auto p : find_all(ld,1
...
1)
cerr << "list bug!\n";
vector vs { "red", "blue", "green", "green", "orange", "green" };
for (auto p : find_all(vs,"green"))
if (∗p!="green")
cerr << "vector bug!\n";
for (auto p : find_all(vs,"green"))
∗p = "vert";
}

Iterators are used to separate algorithms and containers
...
Conversely, a
container knows nothing about the algorithms operating on its elements; all it does is to supply iterators upon request (e
...
, begin() and end())
...


4
...
2 Iterator Types
What are iterators really? Any particular iterator is an object of some type
...
These iterator types can be as different as the containers and
the specialized needs they serve
...

A list iterator must be something more complicated than a simple pointer to an element because
an element of a list in general does not know where the next element of that list is
...


What is common for all iterators is their semantics and the naming of their operations
...
Similarly, ∗ yields
the element to which the iterator refers
...
1
...
Furthermore, users rarely need to know the type of a specific iterator; each
container ‘‘knows’’ its iterator types and makes them available under the conventional names iterator and const_iterator
...

We rarely have to worry about the details of how that type is defined
...
5
...

However, containers are not the only place where we find sequences of elements
...

Consequently, the notion of iterators can be usefully applied to input and output
...
For example:

Section 4
...
3

Stream Iterators

ostream_iterator oo {cout};

107

// write strings to cout

The effect of assigning to ∗oo is to write the assigned value to cout
...
The ++oo is done to
mimic writing into an array through a pointer
...
Again, we must specify the stream to be used and the type of values expected:
istream_iterator ii {cin};

Input iterators are used in pairs representing a sequence, so we must provide an
indicate the end of input
...
Instead, they are provided as
arguments to algorithms
...
begin(),b
...
begin(),b
...
eof() || !os;

// return error state (§2
...
1, §38
...
The ostream_iterator’s second argument is used to delimit output values
...
We read the strings into a vector, then we
sort() them, and then we write them out, eliminating duplicates
...
This can be done by keeping the strings in a set, which does not keep duplicates and keeps its elements in order (§31
...
3)
...
begin(),b
...
begin(),b
...
eof() || !os;

// return error state (§2
...
1, §38
...


4
...
4 Predicates
In the examples above, the algorithms have simply ‘‘built in’’ the action to be done for each element of a sequence
...
For
example, the find algorithm (§32
...
A
more general variant looks for an element that fulfills a specified requirement, a predicate (§3
...
2)
...
A map allows us to
access its elements as a sequence of (key,value) pairs, so we can search a map’s sequence
for a pair where the int is greater than 42:
void f(map& m)
{
auto p = find_if(m
...
end(),Greater_than{42});
//
...
4
...
second>val; }
};

Alternatively, we could use a lambda expression (§3
...
3):
int cxx = count_if(m
...
end(), [](const pair& r) { return r
...
5
...
5
...
Definiteness
...
Output
...
1]
...

The standard library provides dozens of algorithms
...
These standard-library algorithms all take sequences
as inputs (§4
...
A half-open sequence from b to e is referred to as [b:e)
...


4
...
6 Container Algorithms
A sequence is defined by a pair of iterators [begin:end)
...
For example:
sort(v
...
end());

Why don’t we just say sort(v)? We can easily provide that shorthand:
namespace Estd {
using namespace std;
template
void sort(C& c)
{
sort(c
...
end());
}

110

A Tour of C++: Containers and Algorithms

Chapter 4

template
void sort(C& c, Pred p)
{
sort(c
...
end(),p);
}
//
...


4
...
1
...
1
...
1
...
1
...

Remember that standard-library facilities are defined in namespace std; §4
...
2
...
2
...
2, §4
...
2
...
3
...
4
...
4
...
4
...

Prefer compact data structures; §4
...
1
...

If in doubt, use a range-checked vector (such as Vec); §4
...
1
...

Use push_back() or back_inserter() to add elements to a container; §4
...
1, §4
...

Use push_back() on a vector rather than realloc() on an array; §4
...

Catch common exceptions in main(); §4
...
1
...

Know your standard algorithms and prefer them over handwritten loops; §4
...
5
...
5
...


Estd

5
A Tour of C++: Concurrency and Utilities
When you wish to instruct,
be brief
...
1 Introduction
From an end-user’s perspective, the ideal standard library would provide components directly supporting essentially every need
...
However, that is not what the C++ standard library is trying to do
...
Instead, the C++
standard library aims to provide components that are useful to most people in most application
areas
...
In addition, support for a few widely important application areas, such as mathematical computation and text
manipulation, have crept in
...
2 Resource Management
One of the key tasks of any nontrivial program is to manage resources
...
Examples are memory, locks,
sockets, thread handles, and file handles
...
Even for short programs, a leak can become an embarrassment, say by a resource
shortage increasing the run time by orders of magnitude
...
To do this, they rely on the
basic language support for resource management using constructor/destructor pairs to ensure that a
resource doesn’t outlive an object responsible for it
...
2
...
2) and all standard-library containers are implemented in similar ways
...
For example, the technique is used for the standard-library lock classes:
mutex m; // used to protect access to shared data
//
...
manipulate shared data
...
3
...
The corresponding destructor releases the resource
...

This is an application of the ‘‘Resource Acquisition Is Initialization’’ technique (RAII; §3
...
1
...
3)
...
Containers
(such as vector and map), string, and iostream manage their resources (such as file handles and buffers) similarly
...
2
...
3
...
3
...
For example:
void f(int i, int j)
// X* vs
...


Section 5
...
1

unique_ptr

if (i<99) throw Z{};
if (j<77) return;
p−>do_something();
sp−>do_something();
//
...
On the other hand, unique_ptr ensures that its object
is properly destroyed whichever way we exit f() (by throwing an exception, by executing return, or
by ‘‘falling off the end’’)
...

}

// use a local variable

Unfortunately, overuse of new (and of pointers and references) seems to be an increasing problem
...
Its further
uses include passing free-store allocated objects in and out of functions:
unique_ptr make_X(int i)
// make an X and immediately give it to a unique_ptr
{
//
...

return unique_ptr{new X{i}};
}

A unique_ptr is a handle to an individual object (or an array) in much the same way that a vector is
a handle to a sequence of objects
...

The shared_ptr is similar to unique_ptr except that shared_ptrs are copied rather than moved
...
For example:
void f(shared_ptr);
void g(shared_ptr);
void user(const string& name, ios_base::openmode mode)
{
shared_ptr fp {new fstream(name,mode)};
if (!∗fp) throw No_file{}; // make sure the file was properly opened
f(fp);
g(fp);
//
...
Note that f() or g() may spawn a task holding a copy of fp or in some
other way store a copy that outlives user()
...
This is
neither cost free nor exorbitantly expensive, but does make the lifetime of the shared object hard to
predict
...

Given unique_ptr and shared_ptr, we can implement a complete ‘‘no naked new’’ policy
(§3
...
1
...
However, these ‘‘smart pointers’’ are still conceptually pointers and
therefore only my second choice for resource management – after containers and other types that
manage their resources at a higher conceptual level
...
Data races
(§41
...
4) and other forms of confusion are not addressed simply by eliminating the resource management issues
...
’’
• When we share an object, we need pointers (or references) to refer to the shared object, so a
shared_ptr becomes the obvious choice (unless there is an obvious single owner)
...

• A shared polymorphic object typically requires shared_ptrs
...
3
...


5
...
All modern programming languages provide support for this
...
The standard-library support is primarily aimed at supporting systems-level concurrency rather than directly providing sophisticated higher-level concurrency models; those can be supplied as libraries built using the standard-library facilities
...
To allow that, C++ provides a suitable memory model (§41
...
3)
...
This section briefly gives examples of the main standard-library
concurrency support facilities: threads, mutexes, lock() operations, packaged_tasks, and futures
...


Section 5
...
1

Tasks and threads

115

5
...
1 Tasks and threads
We call a computation that can potentially be executed concurrently with other computations a task
...
A task to be executed concurrently with other tasks is launched by constructing a std::thread (found in ) with the task as
its argument
...
4
...
join();
t2
...
To ‘‘join’’ means to
‘‘wait for the thread to terminate
...
In this, threads differ from processes, which
generally do not directly share data
...
3
...
Such communication is typically controlled by locks or other
mechanisms to prevent data races (uncontrolled concurrent access to a variable)
...
Consider possible implementations of the
tasks f (a function) and F (a function object):
void f() { cout << "Hello "; }
struct F {
void operator()() { cout << "Parallel World!\n"; }
};

This is an example of a bad error: Here, f and F() each use the object cout without any form of synchronization
...
The program may produce ‘‘odd’’ output, such as
PaHerallllel o World!

When defining tasks of a concurrent program, our aim is to keep tasks completely separate except
where they communicate in simple and obvious ways
...
For that to work, we just
have to pass arguments, get a result back, and make sure that there is no use of shared data in
between (no data races)
...
3
...
We can easily pass data (or pointers or references to the
data) as arguments
...
4
...
join();
t2
...
F can now use that array and
hopefully no other task accesses vec2 while F is executing
...

The initialization with {f,some_vec} uses a thread variadic template constructor that can accept
an arbitrary sequence of arguments (§28
...
The compiler checks that the first argument can be
invoked given the following arguments and builds the necessary function object to pass to the
thread
...


5
...
3 Returning Results
In the example in §5
...
2, I pass the arguments by non-const reference
...
7)
...
A less obscure technique is to pass the input data by const reference and to pass the location of a place to deposit the result as a separate argument:
void f(const vector& v, double∗ res);// take input from v; place result in *res
class F {
public:
F(const vector& vv, double∗ p) :v{vv}, res{p} { }
void operator()();
// place result in *res

Section 5
...
3

private:
const vector& v;
double∗ res;
};

Returning Results

117

// source of input
// target for output

int main()
{
vector some_vec;
vector vec2;
//
...
join();
t2
...
3
...
1
...
3
...
In that case, the access has to be synchronized so that at most
one task at a time has access
...
g
...

The fundamental element of the solution is a mutex, a ‘‘mutual exclusion object
...
lock())
...

Once a thread has completed its access to the shared data, the unique_lock releases the mutex (with
a call m
...
The mutual exclusion and locking facilities are found in
...
Obviously, this is error-prone,
and equally obviously we try to make the correspondence clear through various language means
...

};

It doesn’t take a genius to guess that for a Record called rec, rec
...

It is not uncommon to need to simultaneously access several resources to perform some action
...
For example, if thread1 acquires mutex1 and then tries to acquire mutex2
while thread2 acquires mutex2 and then tries to acquire mutex1, then neither task will ever proceed
further
...

unique_lock lck1 {m1,defer_lock};
unique_lock lck2 {m2,defer_lock};
unique_lock lck3 {m3,defer_lock};
//
...
manipulate shared data
...
The destructors for the individual unique_locks ensure that the
mutexes are released when a thread leaves the scope
...
In particular, the programmer has to
devise ways of knowing what work has and has not been done by various tasks
...
On the other hand, some people are convinced that sharing must be more efficient than copying arguments and returns
...
On the other hand, modern machines are very good at copying data, especially compact
data, such as vector elements
...


5
...
4
...
The simplest ‘‘event’’ is simply time passing
...
3
...
1

Waiting for Events

using namespace std::chrono;

119

// see §35
...
count() << " nanoseconds passed\n";

Note that I didn’t even have to launch a thread; by default, this_thread refers to the one and only
thread (§42
...
6)
...
See §5
...
1 and
§35
...
The time facilities are found in

...
3
...
A condition_variable is a mechanism allowing one thread to
wait for another
...

Consider the classical example of two threads communicating by passing messages through a
queue
...

};

// object to be communicated

queue mqueue;
condition_variable mcond;
mutex mmutex;

// the queue of messages
// the variable communicating events
// the locking mechanism

The types queue, condition_variable, and mutex are provided by the standard library
...
wait(lck)) /* do nothing */;
auto m = mqueue
...
pop();
lck
...
process m
...
Waiting on condition_variable releases its lock argument until the wait is
over (so that the queue is non-empty) and then reacquires it
...
fill the message
...
push(m);
mcond
...
3
...


5
...
5 Communicating Tasks
The standard library provides a few facilities to allow programmers to operate at the conceptual
level of tasks (work to potentially be done concurrently) rather than directly at the lower level of
threads and locks:
[1] future and promise for returning a value from a task spawned on a separate thread
[2] packaged_task to help launch tasks and connect up the mechanisms for returning a result
[3] async() for launching of a task in a manner very similar to calling a function
...


5
...
5
...
The basic
idea is simple: When a task wants to pass a value to another, it puts the value into a promise
...
We can represent this graphically:
task1:

task2:
set_value()

get()

future

promise
set_exception()

value
If we have a future called fx, we can get() a value of type X from it:
X v = fx
...
If the value couldn’t be computed,
get() might throw an exception (from the system or transmitted from the task from which we were
trying to get() the value)
...
3
...
1

future

and promise

121

The main purpose of a promise is to provide simple ‘‘put’’ operations (called set_value() and
set_exception()) to match future’s get()
...
They are yet another fertile source of puns
...
For example:
void f(promise& px) // a task: place the result in px
{
//
...
compute a value for res
...
set_value(res);
}
catch (
...
set_exception(current_exception());
}
}

The current_exception() refers to the caught exception (§30
...
1
...

To deal with an exception transmitted through a future, the caller of
catch it somewhere
...

try {
X v = fx
...
use v
...
) {
// oops: someone couldn’t compute v
//
...

}
}

5
...
5
...
A packaged_task provides wrapper
code to put the return value or exception from the task into a promise (like the code shown in
§5
...
5
...
If you ask it by calling get_future, a packaged_task will give you the future corresponding
to its promise
...
4
...
6):

122

A Tour of C++: Concurrency and Utilities

Chapter 5

double accum(double∗ beg, double ∗ end, double init)
// compute the sum of [beg:end) starting with the initial value init
{
return accumulate(beg,end,init);
}
double comp2(vector& v)
{
using Task_type = double(double∗,double∗,double);

// type of task

packaged_task pt0 {accum};
packaged_task pt1 {accum};

// package the task (i
...
, accum)

future f0 {pt0
...
get_future()};

// get hold of pt0’s future
// get hold of pt1’s future

double∗ first = &v[0];
thread t1 {move(pt0),first,first+v
...
size()/2,first+v
...

return f0
...
get();

// get the results

}

The packaged_task template takes the type of the task as its template argument (here Task_type, an
alias for double(double∗,double∗,double)) and the task as its constructor argument (here, accum)
...

Please note the absence of explicit mention of locks in this code: we are able to concentrate on
tasks to be done, rather than on the mechanisms used to manage their communication
...


5
...
5
...
It is far from the only model supported by the C++ standard library, but it serves well for a
wide range of needs
...
g
...

To launch tasks to potentially run asynchronously, we can use async():
double comp4(vector& v)
// spawn many tasks if v is large enough
{
if (v
...
begin(),v
...
0);
auto v0 = &v[0];
auto sz = v
...
3
...
3

async()

auto f0 = async(accum,v0,v0+sz/4,0
...
0);
auto f2 = async(accum,v0+sz/2,v0+sz∗3/4,0
...
0);

123

// first quarter
// second quarter
// third quarter
// four th quar ter

return f0
...
get()+f2
...
get(); // collect and combine the results
}

Basically, async() separates the ‘‘call part’’ of a function call from the ‘‘get the result part,’’ and separates both from the actual execution of the task
...
Instead, you think just in terms of tasks that potentially compute their results
asynchronously
...
For example, async() may check whether any idle cores (processors) are available before deciding how many threads to use
...
For example, it can also be used to spawn a task for getting information
from a user, leaving the ‘‘main program’’ active with something else (§42
...
6)
...
4 Small Utility Components
Not all standard-library components come as part of obviously labeled facilities, such as ‘‘containers’’ or ‘‘I/O
...

• Type functions, such as iterator_traits and is_arithmetic, for gaining information about types
...

The point here is that a function or a type need not be complicated or closely tied to a mass of other
functions and types to be useful
...


5
...
1 Time
The standard library provides facilities for dealing with time
...
2

auto t0 = high_resolution_clock::now();
do_work();
auto t1 = high_resolution_clock::now();
cout << duration_cast(t1−t0)
...
Subtracting two time_points gives a duration (a
period of time)
...
That’s what duration_cast does
...
2)
...

Guesses about performance are most unreliable
...
4
...
The standard library provides a variety of type functions to help library implementers and programmers in general to write code that take advantage of aspects of the language,
the standard library, and code in general
...
6
...
For example:
constexpr float min = numeric_limits<float>::min();

// smallest positive float (§40
...
2
...
For example:
constexpr int szi = sizeof(int); // the number of bytes in an int

Such type functions are part of C++’s mechanisms for compile-time computation that allow tighter
type checking and better performance than would otherwise have been possible
...
Here, I just present two facilities provided by the standard library: iterator_traits
(§5
...
2
...
4
...
2)
...
4
...
1 iterator_traits
The standard-library sort() takes a pair of iterators supposed to define a sequence (§4
...
Furthermore, those iterators must offer random access to that sequence, that is, they must be randomaccess iterators
...
In particular, a forward_list is a singly-linked list so subscripting would be expensive and there is no reasonable way
to refer back to a previous element
...
1
...

The standard library provides a mechanism, iterator_traits that allows us to check which kind of
iterator is supported
...
5
...
For example:
void test(vector& v, forward_list& lst)
{
sort(v); // sor t the vector
sort(lst); // sor t the singly-linked list
}

The techniques needed to make that work are generally useful
...
The version taking random-access iterator
arguments is trivial:

Section 5
...
2
...
begin(),v
...
begin(),v
...
3
...
3)
...

The real ‘‘type magic’’ is in the selection of helper functions:
template
void sort(C& c)
{
using Iter = Iterator_type;
sort_helper(c
...
end(),Iterator_category{});
}

Here, I use two type functions: Iterator_type returns the iterator type of C (that is, C::iterator) and
then Iterator_category{} constructs a ‘‘tag’’ value indicating the kind of iterator provided:
• std::random_access_iterator_tag if C’s iterator supports random access
...

Given that, we can select between the two sorting algorithms at compile time
...

The standard-library support for techniques for using iterators, such as tag dispatch, comes in
the form of a simple class template iterator_traits from (§33
...
3)
...
But then you can’t use the
techniques they support to improve your own code
...
4
...
2 Type Predicates
A standard-library type predicate is a simple type function that answers a fundamental question
about types
...
4
...
Other examples are is_class,
is_pod, is_literal_type, has_virtual_destructor, and is_base_of
...
For example:
template
class complex {
Scalar re, im;
public:
static_assert(Is_arithmetic(), "Sorry, I only support complex of arithmetic types");
//
...


5
...
3 pair and tuple
Often, we need some data that is just data; that is, a collection of values, rather than an object of a
class with a well-defined semantics and an invariant for its value (§2
...
3
...
4)
...
Alternatively, we could let the standard library write the definition for us
...
6
...
We can use that to search in a sorted sequence of Records:
auto rec_eq = [](const Record& r1, const Record& r2) { return r1
...
name;};// compare names
void f(const vector& v)
// assume that v is sorted on its "name" field
{
auto er = equal_range(v
...
end(),Record{"Reg"},rec_eq);

Section 5
...
3

pair

for (auto p = er
...
second; ++p)
cout << ∗p;

and tuple

127

// print all equal records
// assume that << is defined for Record

}

The first member of a pair is called first and the second member is called second
...

The standard-library pair (from ) is quite frequently used in the standard library and
elsewhere
...
The make_pair() function makes it easy to create a pair without explicitly mentioning its type (§34
...
4
...
For example:
void f(vector& v)
{
auto pp = make_pair(v
...

}

// pp is a pair::iterator,int>

If you need more than two elements (or less), you can use tuple (from ; §34
...
4
...
A tuple
is a heterogeneous sequence of elements; for example:
tuple t2("Sild",123, 3
...
23);

// the type is deduced
// t is a tuple

string s = get<0>(t); // get first element of tuple
int x = get<1>(t);
double d = get<2>(t);

The elements of a tuple are numbered (starting with zero), rather than named the way elements of
pairs are (first and second)
...
5
...

Like pairs, tuples can be assigned and compared if their elements can be
...
It is less common to need three or more parts to
a result, so tuples are more often found in the implementations of generic algorithms
...
5 Regular Expressions
Regular expressions are a powerful tool for text processing
...
g
...
S
...
In , the standard library provides
support for regular expressions in the form of the std::regex class and its supporting functions
...
It specifies a pattern starting with two letters \w{2} optionally followed by some space \s∗
followed by five digits \d{5} and optionally followed by a dash and four digits −\d{4}
...
Regular expressions are summarized in §37
...
1
...
3
...
1) starting with R"( and terminated by )"
...

The simplest way of using a pattern is to search for it in a stream:
int lineno = 0;
for (string line; getline(cin,line);) {
// read into line buffer
++lineno;
smatch matches;
// matched strings go here
if (regex_search(line,matches,pat))
// search for pat in line
cout << lineno << ": " << matches[0] << '\n';
}

The regex_search(line,matches,pat) searches the line for anything that matches the regular expression
stored in pat and if it finds any matches, it stores them in matches
...
The matches variable is of type smatch
...
The first element, here matches[0], is
the complete match
...


5
...
However, C++ is heavily
used for numerical computation and the standard library reflects that
...
6
...
3)
...
4)
...
For
example:
void f()
{
list lst {1, 2, 3, 4, 5, 9999
...
begin(),lst
...
0); // calculate the sum
cout << s << '\n';
// print 10014
...
6)
...
6
...
6
...
3
...
, the standard
library complex is a template:
template
class complex {
public:
complex(const Scalar& re ={}, const Scalar& im ={});
//
...
For example:
void f(complex<float> fl, complex db)
{
complex ld {fl+sqrt(db)};
db += fl∗3;
fl = pow(1/fl,2);
//
...
For more details, see §40
...


5
...
3 Random Numbers
Random numbers are useful in many contexts, such as testing, games, simulation, and security
...
A random number generator consists of two parts:
[1] an engine that produces a sequence of random or pseudo-random values
...

Examples of distributions are uniform_int_distribution (where all integers produced are equally
likely), normal_distribution (‘‘the bell curve’’), and exponential_distribution (exponential growth);
each for some specified range
...
6
// make a generator

int x = die();

// roll the die: x becomes a value in [1:6]

The standard-library function bind() makes a function object that will invoke its first argument
(here, one_to_six) given its second argument (here, re) as its argument (§33
...
1)
...


130

A Tour of C++: Concurrency and Utilities

Chapter 5

Thanks to its uncompromising attention to generality and performance one expert has deemed the
standard-library random number component ‘‘what every random number library wants to be when
it grows up
...
’’ The using statements makes
what is being done a bit more obvious
...

For novices (of any background) the fully general interface to the random number library can be
a serious obstacle
...

For example:
Rand_int rnd {1,10};
int x = rnd();

// make a random number generator for [1:10]
// x is a number in [1:10]

So, how could we get that? We have to get something like die() inside a class Rand_int:
class Rand_int {
public:
Rand_int(int low, int high) :dist{low,high} { }
int operator()() { return dist(re); }
// draw an int
private:
default_random_engine re;
uniform_int_distribution<> dist;
};

That definition is still ‘‘expert level,’’ but the use of Rand_int() is manageable in the first week of a
C++ course for novices
...
size(); ++i) {
// write out a bar graph
cout << i << '\t';
for (int j=0; j!=mn[i]; ++j) cout << '∗';
cout << endl;
}
}

The output is a (reassuringly boring) uniform distribution (with reasonable statistical variation):
0
1
2
3
4

∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗

Section 5
...
3

Random Numbers

131

There is no standard graphics library for C++, so I use ‘‘ASCII graphics
...

For more information about random numbers, see §40
...


5
...
4 Vector Arithmetic
The vector described in §4
...
1 was designed to be a general mechanism for holding values, to be
flexible, and to fit into the architecture of containers, iterators, and algorithms
...
Adding such operations to vector would be easy, but its
generality and flexibility precludes optimizations that are often considered essential for serious
numerical work
...

};

The usual arithmetic operations and the most common mathematical functions are supported for
valarrays
...
14+a2/a1;
// numeric array operators *, +, /, and =
a2 += a1∗3
...

}

For more details, see §40
...
In particular,
mensional computations
...
6
...
2
...
2
...
4)
...
7 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]

Use resource handles to manage resources (RAII); §5
...

Use unique_ptr to refer to objects of polymorphic type; §5
...
1
...
2
...

Use type-safe mechanisms for concurrency; §5
...

Minimize the use of shared data; §5
...
4
...
3
...

Think in terms of concurrent tasks, rather than threads; §5
...
5
...
4
...
4
...

You can write code to explicitly depend on properties of types; §5
...
2
...
5
...
6
...
6
...


Part II
Basic Facilities
This part describes C++’s built-in types and the basic facilities for constructing programs out of them
...
It also discusses the basic facilities for
composing a C++ program out of logical and physical parts
...
I have long entertained a suspicion, with regard to the decisions of philosophers
upon all subjects, and found in myself a greater inclination to dispute, than assent to
their conclusions
...
When a philosopher
has once laid hold of a favourite principle, which perhaps accounts for many natural
effects, he extends the same principle over the whole creation, and reduces to it every
phænomenon, though by the most violent and absurd reasoning
...
PART I
...

– C
...
Parkinson










The ISO C++ Standard
Implementations; The Basic Source Character Set
Types
Fundamental Types; Booleans; Character Types; Integer Types; Floating-Point Types; Prefixes and Suffixes; void; Sizes; Alignment
Declarations
The Structure of Declarations; Declaring Multiple Names; Names; Scope; Initialization;
Deducing a Type: auto and decltype()
Objects and Values
Lvalues and Rvalues; Lifetimes of Objects
Type Aliases
Advice

6
...
In
this book, references to the standard are of the form §iso
...
3
...
1
...
But don’t
expect the standard to be a tutorial or to be easily accessible by non-experts
...
The standard doesn’t say whether a piece of code is good or bad; it
simply says what a programmer can and cannot rely on from an implementation
...
They do so to access system interfaces and

136

Types and Declarations

Chapter 6

hardware features that cannot be expressed directly in C++ or require reliance on specific implementation details
...
This means that
each implementation must provide a specific, well-defined behavior for a construct and that behavior must be documented
...
However, the behavior
of the initialization of c2 is implementation-defined because the number of bits in a char is implementation-defined
...
5
...
1)
...

Other behaviors are unspecified; that is, a range of possible behaviors are acceptable, but the
implementer is not obliged to specify which actually occur
...
For example,
the exact value returned by new is unspecified
...
2)
...
Such behavior is the price we pay for the ability to operate effectively on a large range of
systems
...
However, 16-bit and 32-bit character sets are not uncommon, and machines with
16-bit and 64-bit pointers are in wide use
...
A typical
example of this practice is to present all dependencies on hardware sizes in the form of constants
and type definitions in some header file
...
2)
...
4
...
3)
...
A construct is deemed undefined by the standard if no reasonable
behavior is required by an implementation
...
For example:
const int size = 4∗1024;
char page[size];
void f()
{
page[size+size] = 7; // undefined
}

Plausible outcomes of this code fragment include overwriting unrelated data and triggering a hardware error/exception
...

Where powerful optimizers are used, the actual effects of undefined behavior can become quite
unpredictable
...
1

The ISO C++ Standard

137

unspecified or implementation-defined rather than undefined
...
In many cases, tools exist to help do this
...
1
...
17
...
1
...
A hosted implementation includes all the standard-library facilities as described in the standard (§30
...

A freestanding implementation may provide fewer standard-library facilities, as long as the following are provided:
Freestanding Implementation Headers
Types
Implementation properties
Integer types
Start and termination
Dynamic memory management
Type identification
Exception handling
Initializer lists
Other run-time support
Type traits
Atomics













§10
...
1
§40
...
7
§43
...
2
...
5
§30
...
1
...
3
...
2
...
3
...
4
...
3

Freestanding implementations are meant for code running with only the most minimal operating
system support
...


6
...
2 The Basic Source Character Set
The C++ standard and the examples in this book are written using the basic source character set
consisting of the letters, digits, graphical characters, and whitespace characters from the U
...
variant of the international 7-bit character set ISO 646-1983 called ASCII (ANSI3
...
This can
cause problems for people who use C++ in an environment with a different character set:
• ASCII contains punctuation characters and operator symbols (such as ], {, and !) that are not
available in some character sets
...

• ASCII doesn’t contain characters (such as ñ, Þ, and Æ) that are used for writing languages
other than English
...
2
...
2)
...
2 Types
Consider:
x = y+f(2);

For this to make sense in a C++ program, the names x, y, and f must be suitably declared
...

Every name (identifier) in a C++ program has a type associated with it
...
For example:
float x;
int y = 7;
float f(int);

// x is a floating-point variable
// y is an integer variable with the initial value 7
// f is a function taking an argument of type int and returning a floating-point number

These declarations would make the example meaningful
...
On the other hand, f is declared to be a function that
takes an int as its argument, so it can be called given the interger 2
...
2
...
3)
...
More extensive and
realistic examples are saved for later chapters
...
You must know these elements, plus the terminology and simple syntax that go with them, in order to complete a real project in C++ and especially to read code written by others
...
Consequently, you
may prefer to skim through this chapter, observing the major concepts, and return later as the need
for understanding more details arises
...
2
...
2
...
2
...
2
...
2
...
2
...
2 Pointer types (such as int∗)
§7
...
7 Reference types (such as double& and vector&&)
In addition, a user can define additional types:
§8
...
4 Enumeration types for representing specific sets of values (enum and enum class)

Section 6
...
1

Fundamental Types

139

The Boolean, character, and integer types are collectively called integral types
...
Enumerations and classes (Chapter 16)
are called user-defined types because they must be defined by users rather than being available for
use without previous declaration, the way fundamental types are
...
The standard library provides
many user-defined types (Chapter 4, Chapter 5)
...
2
...
The assumption is that a computer provides bytes for holding characters, words for holding and computing integer values, some entity most suitable for floating-point computation, and
addresses for referring to those entities
...

For most applications, we could use bool for logical values, char for characters, int for integer
values, and double for floating-point values
...


6
...
2 Booleans
A Boolean, bool, can have one of the two values
results of logical operations
...


A Boolean is used to express the

void f(int a, int b)
{
bool b1 {a==b};
//
...

A common use of bool is as the type of the result of a function that tests some condition (a predicate)
...
Conversely, integers can be implicitly converted to bool values: nonzero integers convert to true and 0
converts to false
...
2
...
5)

int i1 = true;
int i2 {true};

// i1 becomes 1
// i2 becomes 1

If you prefer to use the {}-initializer syntax to prevent narrowing, yet still want to convert an int to a
bool, you can be explicit:

140

Types and Declarations

Chapter 6

void f(int i)
{
bool b {i!=0};
//
...
If the result needs to be converted back to bool,
a 0 is converted to false and a nonzero value is converted to true
...
5
...
5)
...
For example:
void g(int∗ p)
{
bool b = p;
bool b2 {p!=nullptr};

true;

// narrows to true or false
// explicit test against nullptr

if (p) {
// equivalent to p!=nullptr
//
...
The shorter form leaves fewer opportunities for mistakes
...
2
...
C++ provides a variety of character types that reflect that – often bewildering – variety:
• char: The default character type, used for program text
...

• signed char: Like char, but guaranteed to be signed, that is, capable of holding both positive
and negative values
...

• wchar_t: Provided to hold characters of a larger character set such as Unicode (see §7
...
2
...

The size of wchar_t is implementation-defined and large enough to hold the largest character
set supported by the implementation’s locale (Chapter 39)
...

• char32_t: A type for holding 32-bit character sets, such as UTF-32
...
5)
...
2
...

A char variable can hold a character of the implementation’s character set
...
Typically, the
character set is a variant of ISO-646, for example ASCII, thus providing the characters appearing
on your keyboard
...

Serious variations occur between character sets supporting different natural languages and
between character sets supporting the same natural language in different ways
...
The larger and more interesting issue of
how to program in a multilingual, multi-character-set environment is beyond the scope of this book,
although it is alluded to in several places (§6
...
3, §36
...
1, Chapter 39)
...
It is not safe to
assume that:
• There are no more than 127 characters in an 8-bit character set (e
...
, some sets provide 255
characters)
...
g
...

• The alphabetic characters are contiguous (EBCDIC leaves a gap between 'i' and 'j')
...
g
...

• A char fits in 1 byte
...
Also, one could reasonably use a 16-bit Unicode encoding for the
basic chars
...
This
general rule applies even to characters
...
For example, the value of 'b' is 98 in the ASCII character set
...

The possibility of converting a char to an integer raises the question: is a char signed or unsigned?
The 256 values represented by an 8-bit byte can be interpreted as the values 0 to 255 or as the values −127 to 127
...
Unfortunately, the choice of signed or unsigned for a plain char is implementationdefined
...


142

Types and Declarations

Chapter 6

Fortunately, the difference matters only for values outside the 0 to 127 range, and the most common
characters are within that range
...
See
§6
...
3
...

Note that the character types are integral types (§6
...
1) so that arithmetic and bitwise logical
operations (§10
...
For example:
void digits()
{
for (int i=0; i!=10; ++i)
cout << static_cast('0'+i);
}

This is a way of writing the ten digits to cout
...
The resulting int is then converted to a char and written to cout
...


6
...
3
...
This opens the
possibility for some nasty surprises and implementation dependencies
...
On an implementation with
8-bit bytes, the answer depends on the meaning of the ‘‘all ones’’ char bit pattern when extended
into an int
...
On a machine where a char
is signed, the answer is −1
...
However, C++ does not offer a general mechanism for detecting this kind
of problem
...
Unfortunately,
some standard-library functions, such as strcmp(), take plain chars only (§43
...

A char must behave identically to either a signed char or an unsigned char
...
For example:
void f(char c, signed char sc, unsigned char uc)
{
char∗ pc = &uc;
// error : no pointer conversion
signed char∗ psc = pc;
// error : no pointer conversion
unsigned char∗ puc = pc;
// error : no pointer conversion
psc = puc;
// error : no pointer conversion
}

Variables of the three char types can be freely assigned to each other
...
5
...
1) is still undefined
...
2
...
1

c = sc;
c = uc;
sc = uc;
uc = sc;
sc = c;
uc = c;

Signed and Unsigned Characters

143

// OK
// implementation-defined if plain chars are signed and if uc’s value is too large
// implementation defined if uc’s value is too large
// OK: conversion to unsigned
// implementation-defined if plain chars are unsigned and if c’s value is too large
// OK: conversion to unsigned

}

To be concrete, assume that a char is 8 bits:
signed char sc = −160;
unsigned char uc = sc;
cout << uc;

// uc == 116 (because 256-160==116)
// print 't'

char count[256];
++count[sc];
++count[uc];

// assume 8-bit chars
// likely disaster: out-of-range access
// OK

None of these potential problems and confusions occur if you use plain
negative character values
...
2
...
2 Character Literals
A character literal is a single character enclosed in single quotes, for example, 'a' and '0'
...
A character literal can be implicitly converted to its integer value in
the character set of the machine on which the C++ program is to run
...
The use of character literals
rather than decimal notation makes programs more portable
...


Despite their appearance, these are single characters
...
There is no limit to the number of hexadecimal digits in the sequence
...
For example:
Octal

Hexadecimal

Decimal

ASCII

'\6'
'\60'
'\137'

'\x6'
'\x30'
'\x05f'

6
48
95

ACK
'0'
'_'

This makes it possible to represent every character in the machine’s character set and, in particular,
to embed such characters in character strings (see §7
...
2)
...

It is possible to enclose more than one character in a character literal, for example, 'ab'
...
The type of such a multicharacter
literal is int
...
The notation is hard enough to read without having to worry about
whether or not the character after a constant is a digit
...

Consider these examples:
char v1[] = "a\xah\129";
char v2[] = "a\xah\127";
char v3[] = "a\xad\127";
char v4[] = "a\xad\0127";

// 6 chars: 'a' '\xa' 'h' '\12' '9' '\0'
// 5 chars: 'a' '\xa' 'h' '\127' '\0'
// 4 chars: 'a' '\xad' '\127' '\0'
// 5 chars: 'a' '\xad' '\012' '7' '\0'

Wide character literals are of the form L'ab' and are of type wchar_t
...

A C++ program can manipulate character sets that are much richer than the 127-character
ASCII set, such as Unicode
...
For example:
U'\UFADEBEEF'
u'\uDEAD'
u'\xDEAD'

The shorter notation u'\uXXXX' is equivalent to U'\U0000XXXX' for any hexadecimal digit X
...
The meaning of the hexadecimal number is defined by the ISO/IEC 10646 standard and such values are called universal
character names
...
2
...
2
...
2
...
3, §iso
...
14
...
E
...
2
...
In addition, integers come in four sizes: short int, ‘‘plain’’ int, long int, and long long int
...
Similarly, short is
a synonym for short int, unsigned for unsigned int, and signed for signed int
...


Section 6
...
4

Integer Types

145

The unsigned integer types are ideal for uses that treat storage as a bit array
...

Attempts to ensure that some values are positive by declaring variables unsigned will typically be
defeated by the implicit conversion rules (§10
...
1, §10
...
2
...

Unlike plain chars, plain ints are always signed
...

If you need more detailed control over integer sizes, you can use aliases from (§43
...
The plain integer types have well-defined minimal sizes (§6
...
8), so the
are sometimes redundant and can be overused
...
These types must behave like integers and are considered integer types
when considering conversions and integer literal values, but they usually have greater range
(occupy more space)
...
2
...
1 Integer Literals
Integer literals come in three guises: decimal, octal, and hexadecimal
...
3
...

A literal starting with zero followed by x or X (0x or 0X) is a hexadecimal (base 16) number
...
For example:
Decimal

Octal

2
63
83

0
02
077
0123

Hexadecimal
0x0
0x2
0x3f
0x63

The letters a, b, c, d, e, and f, or their uppercase equivalents, are used to represent 10, 11, 12, 13, 14,
and 15, respectively
...

Using these notations to express genuine numbers can lead to surprises
...
Had more bits been used to represent an integer, it would have been the positive decimal number 65535
...
Similarly, the suffix L can be used
to write explicitly long literals
...

Combinations of suffixes are allowed
...
2
...
2)
...
5),
constexpr (§10
...
4) initializers
...
2
...
2 Types of Integer Literals
In general, the type of an integer literal depends on its form, value, and suffix:
• If it is decimal and has no suffix, it has the first of these types in which its value can be represented: int, long int, long long int
...

• If it is suffixed by u or U, its type is the first of these types in which its value can be represented: unsigned int, unsigned long int, unsigned long long int
...

• If it is octal or hexadecimal and suffixed by l or L, its type is the first of these types in which
its value can be represented: long int, unsigned long int, long long int, unsigned long long int
...

• If it is decimal and is suffixed by ll or LL, its type is long long int
...

• If it is suffixed by llu, llU, ull, Ull, LLu, LLU, uLL, or ULL, its type is unsigned long long int
...
Similarly, 0XA000 is of type int on a machine with 32-bit ints but
of type unsigned int on a machine with 16-bit ints
...


6
...
5 Floating-Point Types
The floating-point types represent floating-point numbers
...
There are three floating-point
types: float (single-precision), double (double-precision), and long double (extended-precision)
...

Choosing the right precision for a problem where the choice matters requires significant understanding of floating-point computation
...


6
...
5
...
Again, a compiler ought to warn about floating-point literals that are too large to be represented
...
2
...
1

1
...
23

Floating-Point Literals

0
...


1
...
2e10

1
...
For example, 65
...
43

e



147

e−21

is

21

If you want a floating-point literal of type float, you can define one using the suffix f or F:
3
...
0f

2
...
9e−3f

If you want a floating-point literal of type long double, you can define one using the suffix l or L:
3
...
0L

2
...
9e−3L

6
...
6 Prefixes and Suffixes
There is a minor zoo of suffixes indicating types of literals and also a few prefixes:
Arithmetic Literal Prefixes and Suffixes
∗fix
Meaning
Example
Reference

Notation
0
0x
u
l
ll

0X
U
L
LL

f
e

...
2
...
2
§iso
...
14
...
2
...
2
§iso
...
14
...
2
...
2
§iso
...
14
...
2
...
4
§iso
...
14
...
2
...
3
§iso
...
14
...
2
...
3
§iso
...
14
...
2
...
5
§iso
...
14
...
2
...
5
§iso
...
14
...
2
...
5
§iso
...
14
...
3

char
char16_t
char32_t
wchar_t

'c'
u'c'
U'c'
L'c'

string
raw string
UTF-8 string
UTF-16 string
UTF-32 string
wchar_t string

"mess"
R"(\b)"
u8"foo"
u"foo"
U"foo"
L"foo"

§6
...
4
...
2
...
1
§6
...
4
...
2
...
1
§6
...
4
...
2
...
1
§6
...
5
...
2
...
1
§6
...
3
...
2
...
2
§6
...
3
...
2
...
2
§7
...
2
§7
...
2
...
3
...
2
§7
...
2
...
3
...
2
§7
...
2
...
3
...
’’
Obviously, we could also consider
...
However, I consider the nomenclature less important than giving an overview of the
bewildering variety of literals
...

For example:

148

Types and Declarations

1LU
2UL
3ULL
4LLU
5LUL

Chapter 6

// unsigned long
// unsigned long
// unsigned long long
// unsigned long long
// error

The suffixes l and L can be used for floating-point literals to express long double
...
0L

// long int
// long double

Combinations of R, L, and u prefixes are allowed, for example, uR"∗∗(foo\(bar))∗∗"
...
3
...
2)
...
For example, by defining a
user-defined literal operator (§19
...
6), we can get
"foo bar"s
123_km

// a literal of type std::string
// a literal of type Distance

Suffixes not starting with _ are reserved for the standard library
...
2
...
It can, however, be used only as part of a more
complicated type; there are no objects of type void
...
For example:
void x;
void& r;
void f();
void∗ pv;

// error: there are no void objects
// error: there are no references to void
// function f does not return a value (§12
...
4)
// pointer to object of unknown type (§7
...
1)

When declaring a function, you must specify the type of the value returned
...
However, that would make a mess of the grammar (§iso
...
Consequently, void is used as a ‘‘pseudo
return type’’ to indicate that a function doesn’t return a value
...
2
...
1)
...
Why should you bother? People who program on a variety of systems or
use a variety of compilers care a lot because if they don’t, they are forced to waste time finding and
fixing obscure bugs
...
’’ This is a narrow and shortsighted view
...
In addition, programs often need to be compiled with other compilers for the same system,
and even a future release of your favorite compiler may do some things differently from the current

Section 6
...
8

Sizes

149

one
...

It is relatively easy to limit the impact of implementation-dependent language features
...
Using standard-library facilities
wherever feasible is one approach
...
On many machines, there are significant differences in memory requirements, memory access
times, and computation speed among the different varieties of fundamental types
...
Writing truly portable low-level code is harder
...
3
...
2 inch to a byte), a megabyte of memory would stretch about 3 miles (5 km) to
the right
...
The size of an object or type can be obtained using the sizeof operator
(§10
...
This is what is guaranteed about sizes of fundamental types:






1 ≡ sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long)
1 ≤ sizeof(bool) ≤ sizeof(long)
sizeof(char) ≤ sizeof(wchar_t) ≤ sizeof(long)
sizeof(float) ≤ sizeof(double) ≤ sizeof(long double)
sizeof(N) ≡ sizeof(signed N) ≡ sizeof(unsigned N)

≤ sizeof(long long)

150

Types and Declarations

Chapter 6

In that last line, N can be char, short, int, long, or long long
...
A char can hold a character of
the machine’s character set
...
Similarly, the int type is supposed to be chosen to be the most suitable for holding
and manipulating integers on a given computer; it is typically a 4-byte (32-bit) word
...
For example, there are machines with 32-bit chars
...
Note that it is not guaranteed that
sizeof(long) ...
For example:
#include
// §40
...
2) are constexpr (§10
...

The fundamental types can be mixed freely in assignments and expressions
...
5)
...
Conversions that are not value-preserving are best avoided (§2
...
2, §10
...
2
...

If you need a specific size of integer, say, a 16-bit integer, you can #include the standard header
that defines a variety of types (or rather type aliases; §6
...
For example:
int16_t x {0xaabb};
int64_t xxxx {0xaaaabbbbccccdddd};
int_least16_t y;
int_least32_t yy
int_fast32_t z;

// 2 bytes
// 8 bytes
// at least 2 bytes (just like int)
// at least 4 bytes (just like long)
// the fastest int type with at least 4 bytes

The standard header defines an alias that is very widely used in both standard-library declarations and user code: size_t is an implementation-defined unsigned integer type that can hold the
size in bytes of every object
...
For
example:
void∗ allocate(size_t n); // get n bytes

Similarly, defines the signed integer type ptrdiff_t for holding the result of subtracting two
pointers to get a number of elements
...
2
...
2
...
In addition, on some
machine architectures, the bytes used to hold it must have proper alignment for the hardware to
access it efficiently (or in extreme cases to access it at all)
...
Of course, this is all very implementation specific, and for most programmers
completely implicit
...
Where alignment most often becomes visible is in object layouts: sometimes
structs contain ‘‘holes’’ to improve alignment (§8
...
1)
...
For example:
auto ac = alignof('c');
auto ai = alignof(1);
auto ad = alignof(2
...
Instead, we can use the type specifier alignas: alignas(T) means ‘‘align just like a T
...
size(),bufmax/sizeof(X));
uninitialized_copy(vx
...
begin()+max,buffer);
//
...
3 Declarations
Before a name (identifier) can be used in a C++ program, it must be declared
...
For example:
char ch;
string s;
auto count = 1;
const double pi {3
...
2
...
4
...
5)
// type name

As can be seen from these examples, a declaration can do more than simply associate a type with a
name
...
A definition is a declaration that supplies all
that is needed in a program for the use of an entity
...
A different terminology deems declarations
parts of an interface and definitions parts of an implementation
...
2
...

Assuming that these declarations are in the global scope (§6
...
4), we have:
char ch;
auto count = 1;
const char∗ name = "Njal";

// set aside memory for a char and initialize it to 0
// set aside memory for an int initialized to 1
// set aside memory for a pointer to char
// set aside memory for a string literal "Njal"
// initialize the pointer with the address of that string literal

struct Date { int d, m, y; };
int day(Date∗ p) { return p−>d; }

// Date is a struct with three members
// day is a function that executes the specified code

using Point = std::complex;// Point is a name for std::complex

Of the declarations above, only three are not also definitions:
double sqrt(double);
extern int error_number;
struct User;

// function declaration
// variable declaration
// type name declaration

That is, if used, the entity they refer to must be defined elsewhere
...
*/ }
int error_number = 1;
struct User { /*
...
2
...
However, there can be many declarations
...
So, this fragment has two errors:
int count;
int count;

// error : redefinition

Section 6
...
2):
extern int error_number;
extern int error_number; // OK: redeclaration

Some definitions explicitly specify a ‘‘value’’ for the entities they define
...
1415926535897};

// Point is a name for std::complex

For types, aliases, templates, functions, and constants, the ‘‘value’’ is permanent
...
For example:
void f()
{
int count {1};
// initialize count to 1
const char∗ name {"Bjarne"}; // name is a variable that points to a constant (§7
...
3
...
3
...

Any declaration that specifies a value is a definition
...
3
...
A)
...
However, without too
many radical simplifications, we can consider a declaration as having five parts (in order):
• Optional prefix specifiers (e
...
, static or virtual)
• A base type (e
...
, vector or const int)
• A declarator optionally including a name (e
...
, p[7], n, or ∗(∗)[])
• Optional suffix function specifiers (e
...
, const or noexcept)
• An optional initializer or function body (e
...
, ={7,5,3} or {return x;})
Except for function and namespace definitions, a declaration is terminated by a semicolon
...

A specifier is an initial keyword, such as virtual (§3
...
3, §20
...
2), extern (§15
...
2
...


154

Types and Declarations

Chapter 6

A declarator is composed of a name and optionally some declarator operators
...
7
...
7
...
However, ∗, [], and () were
designed to mirror their use in expressions (§10
...
Thus, ∗ is prefix and [] and () are postfix
...
Consequently, char∗kings[] is an array
of pointers to char, whereas char(∗kings)[] is a pointer to an array of char
...
2
...
For example:
const c = 7;

// error : no type

gt(int a, int b) // error : no return type
{
return (a>b) ? a : b;
}
unsigned ui;
long li;

// OK: ‘‘unsigned’’means ‘‘unsigned int’’
// OK: ‘‘long’’ means ‘‘long int’’

In this, standard C++ differs from early versions of C and C++ that allowed the first two examples
by considering int to be the type when none was specified (§44
...
This ‘‘implicit int’’ rule was a
source of subtle errors and much confusion
...

Some type names don’t even look much like names, such as decltype(f(x)) (the return type of a call
f(x); §6
...
6
...

The volatile specifier is described in §41
...

The alignas() specifier is described in §6
...
9
...
3
...
The declaration simply contains a list
of comma-separated declarators
...
3
...
For example:
int∗ p, y;
// int* p; int y; NOT int* y;
int x, ∗q;
// int x; int* q;
int v[10], ∗pv; // int v[10]; int* pv;

Such declarations with multiple names and nontrivial declarators make a program harder to read
and should be avoided
...
3
...
The first character must be a letter
...
C++ imposes no limit on the number of characters in a name
...
Some
run-time environments also make it necessary to extend or restrict the set of characters accepted in
an identifier
...
g
...
A
C++ keyword (§6
...
3
...

Examples of names are:
hello
DEFINED
var0

this_is_a_most_unusually_long_identifier_that_is_better_avoided
foO
bAr
u_name
HorseSense
var1
CLASS
_class
___

Examples of character sequences that cannot be used as identifiers are:
012
pay
...
name

class
if

3var

Nonlocal names starting with an underscore are reserved for special facilities in the implementation
and the run-time environment, so such names should not be used in application programs
...
g
...
17
...
4
...

When reading a program, the compiler always looks for the longest string of characters that
could make up a name
...

Also, elseif is a single name, not the keyword else followed by the keyword if
...
In general, it is best to avoid
names that differ only in subtle ways
...
Consequently, l0, lO, l1, ll, and I1l are poor choices for identifier names
...

Names from a large scope ought to have relatively long and reasonably obvious names, such as
vector, Window_with_border, and Department_number
...
Functions (Chapter 12), classes
(Chapter 16), and namespaces (§14
...
1) can be used to keep scopes small
...


156

Types and Declarations

Chapter 6

Choose names to reflect the meaning of an entity rather than its implementation
...
4)
...
g
...

• The compiler is better at keeping track of types than you are
...
g
...

• Any system of type abbreviations you can come up with will become overelaborate and
cryptic as the variety of types you use increases
...

Try to maintain a consistent naming style
...

Also, use all capitals for macros (if you must use macros (§12
...
Use underscores to separate words in an identifier;
number_of_elements is more readable than numberOfElements
...
Be consistent in your use of abbreviations and acronyms
...

phone_book

6
...
3
...


and_eq
break
class
decltype
else
for
long
not_eq
protected
signed
switch
try
using
xor

asm
case
compl
default
enum
friend
mutable
nullptr
public
sizeof
template
typedef
virtual
xor_eq

auto
catch
const
delete
explicit
goto
namespace
operator
register
static
this
typeid
void

Section 6
...
4

Scope

157

6
...
4 Scope
A declaration introduces a name into a scope; that is, a name can be used only in a specific part of
the program text
...
4) is called a local
name
...
A block is a section of code delimited by a {} pair
...

• Class scope: A name is called a member name (or a class member name) if it is defined in a
class outside any function, class (Chapter 16), enum class (§8
...
1), or other namespace
...

• Namespace scope: A name is called a namespace member name if it is defined in a namespace (§14
...
1) outside any function, lambda (§11
...
4
...
Its scope extends from the point of declaration to the end of
its namespace
...
2)
...
4
...
3
...
The scope of a global name
extends from the point of declaration to the end of the file in which its declaration occurs
...
2)
...

• Statement scope: A name is in a statement scope if it is defined within the () part of a for-,
while-, if-, or switch-statement
...
All names in statement scope are local names
...
6) is in scope from its point of declaration until the end of the
function
...

That is, a name can be redefined to refer to a different entity within a block
...
For example:
int x;
void f()
{
int x;
x = 1;
{
int x;
x = 2;
}
x = 3;
}
int∗ p = &x;

// global x

// local x hides global x
// assign to local x
// hides first local x
// assign to second local x
// assign to first local x

// take address of global x

158

Types and Declarations

Chapter 6

Hiding names is unavoidable when writing large programs
...
Because such errors are relatively rare, they can be very difficult to find
...

Using names such as i and x for global variables or for local variables in a large function is asking
for trouble
...
For example:
int x;
void f2()
{
int x = 1; // hide global x
::x = 2;
// assign to global x
x = 2;
// assign to local x
//
...

The scope of a name that is not a class member starts at its point of declaration, that is, after the
complete declarator and before the initializer
...
For example:
int x = 97;
void f3()
{
int x = x;
}

// perverse: initialize x with its own (uninitialized) value

A good compiler warns if a variable is used before it has been initialized
...
For example:
int x = 11;
void f4()
{
int y = x;
int x = 22;
y = x;
}

// perverse: use of two different objects both called x in a single scope
// use global x: y = 11
// use local x: y = 22

Again, such subtleties are best avoided
...

For example:
void f5(int x)
{
int x;
}

// error

Section 6
...
4

Scope

159

This is an error because x is defined twice in the same scope
...
This
allows us to use conventional names for loop variables repeatedly in a function
...
size(), ++i) cout << v[i] << '\n';
for (auto i : {1, 2, 3, 4, 5, 6, 7}) cout << i << '\n';
}

This contains no name clashes
...
4
...


6
...
5 Initialization
If an initializer is specified for an object, that initializer determines the initial value of an object
...
It is clearer
and less error-prone than the alternatives
...
The two forms using = are what you use in
C
...
For example:
int x1 = 0;
char c1 = 'z';

However, anything much more complicated than that is better done using {}
...
8
...
4)
...
For example,
char to int is allowed, but not int to char
...
For example, float to double is allowed, but not double to float
...

• An integer value cannot be converted to a floating-point type
...
9, x2 becomes 7
char c2 = val2;
// if val2==1025, c2 becomes 1

160

Types and Declarations

Chapter 6

int x3 {val};
char c3 {val2};

// error : possible truncation
// error : possible narrowing

char c4 {24};
char c5 {264};

// OK: 24 can be represented exactly as a char
// error (assuming 8-bit chars): 264 cannot be represented as a char

int x4 {2
...

}

See §10
...

There is no advantage to using {} initialization, and one trap, when using auto to get the type
determined by the initializer
...
3
...
2)
...

It is possible to define a class so that an object can be initialized by a list of values and alternatively be constructed given a couple of arguments that are not simply values to be stored
...
Most types do not
offer such confusing alternatives – even most vectors do not; for example:
vector v1{"hello!"};
vector v2("hello!");

// v1 is a vector of 1 element with the value "hello!"
// error : no vector constructor takes a string literal

So, prefer {} initialization over alternatives unless you have a strong reason not to
...
For example:
int x4 {};
double d4 {};
char∗ p {};
vector v4{};
string s4 {};

// x4 becomes 0
// d4 becomes 0
...
For integral types, the default value is a suitable representation of
zero
...
2
...
For user-defined types, the default value (if
any) is determined by the type’s constructors (§17
...
3)
...
2
...

Initialization of particular kinds of objects is discussed where appropriate:
• Pointers: §7
...
2, §7
...
2, §7
...
7
...
7
...
3
...
3
...
3
...
4
Classes: §17
...
1 (not using constructors), §17
...
2 (using constructors), §17
...
3 (default),
§17
...
5 (copy and move)
User-defined containers: §17
...
4

6
...
5
...
If you do that
– and that has unfortunately been common – the situation is more complicated
...
The only really good case for an uninitialized variable is a large input buffer
...
get(buf,max); // read at most max characters into buf

We could easily have initialized buf:
char buf[max] {};

// initialize every char to 0

By redundantly initializing, we would have suffered a performance hit which just might have been
significant
...
g
...

If no initializer is specified, a global (§6
...
4), namespace (§14
...
1), local static (§12
...
8), or
static member (§16
...
12) (collectively called static objects) is initialized to {} of the appropriate
type
...
0

Local variables and objects created on the free store (sometimes called dynamic objects or heap
objects; §11
...
3
...
For example:
void f()
{
int x;
char buf[1024];

// x does not have a well-defined value
// buf[i] does not have a well-defined value

int∗ p {new int};
char∗ q {new char[1024]};
string s;
vector v;

// s=="" because of string’s default constructor
// v=={} because of vector’s default constructor

string∗ ps {new string};
//
...
For example:
void ff()
{
int x {};
char buf[1024]{};

// x becomes 0
// buf[i] becomes 0 for all i

int∗ p {new int{10}};
char∗ q {new char[1024]{}};

// *p becomes 10
// q[i] becomes 0 for all i

//
...


6
...
5
...
More complicated
objects can require more than one value as an initializer
...
For example:
int a[] = { 1, 2 };
struct S { int x, string s };
S s = { 1, "Helios" };
complex z = { 0, pi };
vector v = { 0
...
1, 2
...
3 };

// array initializer
// struct initializer
// use constructor
// use list constructor

For C-style initialization of arrays, see §7
...
1
...
2
...
3
...
2
...
For initializer-list constructors, see §17
...
4
...
However, some prefer to add it to emphasize that a set of
values are used to initialize a set of member variables
...
3, §16
...
5)
...
3);

// use constructor
// use constructor : v gets 10 elements initialized to 3
...
1)
...
For example:
complex z1(1,2);
complex f1();

// function-style initializer (initialization by constructor)
// function declaration

complex z2 {1,2};
complex f2 {};

// initialization by constructor to {1,2}
// initialization by constructor to the default value {0,0}

Note that initialization using the {} notation does not narrow (§6
...
5)
...
For example:
auto x1 {1,2,3,4};
// x1 is an initializer_list
auto x2 {1
...
25, 3
...
0,2};
// error: cannot deduce the type of {1
...
3
...
2)

Section 6
...
5
...
3
...

• decltype(expr) for deducing the type of something that is not a simple initializer, such as the
return type for a function or the type of a class member
...


6
...
6
...

Instead, we can let the variable have the type of its initializer
...
That is, auto is a placeholder for the type of
the initializer
...
The
harder the type is to write and the harder the type is to know, the more useful auto becomes
...
begin(); p!=arg
...
begin(); p!=arg
...
Also, it is more resilient
to code changes
...
So, unless there is a good reason not to,
use auto in small scopes
...
That is, compared to
using a specific type, using auto can delay the detection of type errors
...

}

If auto causes surprises, the best cure is typically to make functions smaller, which most often is a
good idea anyway (§12
...


164

Types and Declarations

Chapter 6

We can decorate a deduced type with specifiers and modifiers (§6
...
1), such as const and & (reference; §7
...
For example:
void f(vector& v)
{
for (const auto& x : v) {
//
...

Note that the type of an expression is never a reference because references are implicitly dereferenced in expressions (§7
...
For example:
void g(int& v)
{
auto x = v;
auto& y = v;
}

// x is an int (not an int&)
// y is an int&

6
...
6
...
For example:
char v1 = 12345;
int v2 = 'c';
T v3 = f();

// 12345 is an int
// 'c' is a char

By using the {}-initializer syntax for such definitions, we minimize the chances for unfortunate conversions:
char v1 {12345};
int v2 {'c'};
T v3 {f()};

// error : narrowing
// fine: implicit char->int conversion
// works if and only if the type of f() can be implicitly converted to a T

When we use auto, there is only one type involved, the type of the initializer, and we can safely use
the = syntax:
auto v1 = 12345;
auto v2 = 'c';
auto v3 = f();

// v1 is an int
// v2 is a char
// v3 is of some appropriate type

In fact, it can be an advantage to use the
prise someone:
auto v1 {12345};
auto v2 {'c'};
auto v3 {f()};

=

syntax with

// v1 is a list of int
// v2 is a list of char
// v3 is a list of some appropriate type

This is logical
...
3
...
2

auto x0 {};
auto x1 {1};
auto x2 {1,2};
auto x3 {1,2,3};

auto

and {}-lists

165

// error: cannot deduce a type
// list of int with one element
// list of int with two elements
// list of int with three elements

The type of a homogeneous list of elements of type T is taken to be of type initializer_list
(§3
...
1
...
3
...
In particular, the type of x1 is not deduced to be int
...
’’

6
...
6
...
But sometimes, we want to have a type
deduced without defining an initialized variable
...
This is mostly useful in generic programming
...
What should be
the type of the result of the addition? A matrix, of course, but what might its element type be? The
obvious answer is that the element type of the sum is the type of the sum of the elements
...
1) to be able to express the return type in terms of the arguments: Matrix
...

In the definition, I again need decltype() to express Matrix’s element type:
template
auto operator+(const Matrix& a, const Matrix& b) −> Matrix
{
Matrix res;
for (int i=0; i!=a
...
cols(); ++j)
res(i,j) += a(i,j) + b(i,j);
return res;
}

6
...
g
...
g
...
Consequently, we need a name for
‘‘something in memory
...
That is,
an object is a contiguous region of storage; an lvalue is an expression that refers to an object
...
’’ However, not every lvalue may be used on the left-hand side of an assignment; an

166

Types and Declarations

Chapter 6

lvalue can refer to a constant (§7
...
An lvalue that has not been declared const is often called a
modifiable lvalue
...
2
...
3
...


6
...
1 Lvalues and Rvalues
To complement the notion of an lvalue, we have the notion of an rvalue
...
g
...

If you need to be more technical (say, because you want to read the ISO C++ standard), you
need a more refined view of lvalue and rvalue
...

• Movable: The object may be moved from (i
...
, we are allowed to move its value to another
location and leave the object in a valid but unspecified state, rather than copying; §17
...

It turns out that three of the four possible combinations of those two properties are needed to precisely describe the C++ language rules (we have no need for objects that do not have identity and
cannot be moved)
...
The other
alternatives are prvalue (‘‘pure rvalue’’), glvalue (‘‘generalized lvalue’’), and xvalue (‘‘x’’ for ‘‘extraordinary’’ or ‘‘expert only’’; the suggestions for the meaning of this ‘‘x’’ have been quite imaginative)
...

}

// move vs to v2

Here, std::move(vs) is an xvalue: it clearly has identity (we can refer to it as vs), but we have explicitly given permission for it to be moved from by calling std::move() (§3
...
2, §35
...
1)
...
Note
that every expression is either an lvalue or an rvalue, but not both
...
4
...
Objects of types without a declared constructor, such as an int, can be considered to
have default constructors and destructors that do nothing
...
4
...
1
...
2
...
Such objects are sometimes called automatic objects
...

• Static: Objects declared in global or namespace scope (§6
...
4) and statics declared in functions (§12
...
8) or classes (§16
...
12) are created and initialized once (only) and ‘‘live’’ until
the program terminates (§15
...
3)
...
A static object has
the same address throughout the life of a program execution
...
3
...
3)
...
2)
...
g
...
If they
are bound to a reference, their lifetime is that of the reference; otherwise, they ‘‘live’’ until
the end of the full expression of which they are part
...
Typically, temporary objects are automatic
...
2
...

Static and automatic are traditionally referred to as storage classes
...


6
...
Possible reasons include:
• The original name is too long, complicated, or ugly (in some programmer’s eyes)
...

• A specific type is mentioned in one place only to simplify maintenance
...

};

// every container has a value_type

168

Types and Declarations

template
class list {
using value_type = T;
//
...
That is, an
alias refers to the type for which it is an alias
...
4) and classes (Chapter 16)
...
For example:
typedef int int32_t;
typedef short int16_t;
typedef void(∗PtoF)(int);

// equivalent to ‘‘using int32_t = int;’’
// equivalent to ‘‘using int16_t = short;’’
// equivalent to ‘‘using PtoF = void(*)(int);’’

Aliases are used when we want to insulate our code from details of the underlying machine
...
Having written our code in
terms of int32_t, rather than ‘‘plain int,’’ we can port our code to a machine with sizeof(int)==2 by
redefining the single occurrence of int32_t in our code to use a longer integer:
using int32_t = long;

The _t suffix is conventional for aliases (‘‘typedefs’’)
...
7)
...
3
...

The using keyword can also be used to introduce a template alias (§23
...
For example:
template
using Vector = std::vector>;

We cannot apply type specifiers, such as unsigned, to an alias
...
6 Advice
[1]
[2]
[3]
[4]
[5]

For the final word on language definition issues, see the ISO C++ standard; §6
...

Avoid unspecified and undefined behavior; §6
...

Isolate code that must depend on implementation-defined behavior; §6
...

Avoid unnecessary assumptions about the numeric value of characters; §6
...
3
...
5
...
1
...
2
...
1
...
6

[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]
[14]
[15]
[16]
[17]
[18]
[19]
[20]
[21]
[22]
[23]

Advice

169

Avoid ‘‘magic constants’’; §6
...
4
...

Avoid unnecessary assumptions about the size of integers; §6
...
8
...
2
...

Prefer plain char over signed char and unsigned char; §6
...
3
...

Beware of conversions between signed and unsigned types; §6
...
3
...

Declare one name (only) per declaration; §6
...
2
...
3
...

Avoid similar-looking names; §6
...
3
...
3
...

Maintain a consistent naming style; §6
...
3
...
3
...

Keep scopes small; §6
...
4
...
3
...

Prefer the {}-initializer syntax for declarations with a named type; §6
...
5
...
3
...

Avoid uninitialized variables; §6
...
5
...

Use an alias to define a meaningful name for a built-in type in cases in which the built-in type
used to represent a value might change; §6
...

Use an alias to define synonyms for types; use enumerations and classes to define new types;
§6
...


This page intentionally left blank

7
Pointers, Arrays, and References
The sublime and the ridiculous
are often so nearly related that
it is difficult to class them separately
...
1 Introduction
This chapter deals with the basic language mechanisms for referring to memory
...
’’ That is, they reside at a
specific address in memory, and an object can be accessed if you know its address and its type
...


172

Pointers, Arrays, and References

Chapter 7

7
...
’’ That is, a variable of type T∗ can hold the address of an
object of type T
...
This operation is also called indirection
...
For example:
char c = 'a';
char∗ p = &c; // p holds the address of c; & is the address-of operator
char c2 = ∗p; // c2 == ’a’; * is the dereference operator

The object pointed to by p is c, and the value stored in c is 'a', so the value of ∗p assigned to c2 is 'a'
...
4)
...
Most machines can address a byte
...
On the other hand, few machines can directly address
an individual bit
...
Note that a bool occupies at least as much space as
a char (§6
...
8)
...
1
...
2
...
2
...

The ∗, meaning ‘‘pointer to,’’ is used as a suffix for a type name
...
3
...
A for the complete grammar
...
5
...
6
...
2
...
A void∗ is used for that
...
’’

Section 7
...
1

void∗

173

A pointer to any type of object can be assigned to a variable of type void∗, but a pointer to function (§12
...
6) cannot
...
Other operations would be unsafe because the compiler cannot know what kind of
object is really pointed to
...
To use a
void∗, we must explicitly convert it to a pointer to a specific type
...
5
...
For example, a machine may assume that every double is allocated on an 8-byte boundary
...
This form of explicit type conversion is inherently unsafe and ugly
...
5
...

The primary use for void∗ is for passing pointers to functions that are not allowed to make
assumptions about the type of the object and for returning untyped objects from functions
...

Functions using void∗ pointers typically exist at the very lowest level of the system, where real
hardware resources are manipulated
...
Where used for optimization, void∗ can be hidden behind
a type-safe interface (§27
...
1)
...
5) and pointers to members (§20
...


7
...
2 nullptr
The literal nullptr represents the null pointer, that is, a pointer that does not point to an object
...


174

Pointers, Arrays, and References

Chapter 7

Before nullptr was introduced, zero (0) was used as a notation for the null pointer
...
Zero (0) is an int
...
5
...
3) allow 0 to be
used as a constant of pointer or pointer-to-member type
...
For example:
int∗ p = NULL; // using the macro NULL

However, there are differences in the definition of NULL in different implementations; for example,
NULL might be 0 or 0L
...
2
...
3
...


7
...
’’ The elements are indexed from 0
to size−1
...
a[31]

You can access an array using the subscript operator, [], or through a pointer (using operator
operator []; §7
...
For example:



or

void f()
{
int aa[10];
aa[6] = 9;
// assign to aa’s 7th element
int x = aa[99]; // undefined behavior
}

Access out of the range of an array is undefined and usually disastrous
...

The number of elements of the array, the array bound, must be a constant expression (§10
...
If
you need variable bounds, use a vector (§4
...
1, §31
...
For example:
void f(int n)
{
int v1[n];
vector v2(n);
}

// error: array size not a constant expression
// OK: vector with n int elements

Multidimensional arrays are represented as arrays of arrays (§7
...
2)
...
If what
you want is a simple fixed-length sequence of objects of a given type in memory, an array is the
ideal solution
...


Section 7
...
4
...
For example:
int a1[10];

// 10 ints in static storage

void f()
{
int a2 [20];
int∗p = new int[40];
//
...
There is no array assignment, and the name of an array implicitly converts to a pointer to
its first element at the slightest provocation (§7
...
In particular, avoid arrays in interfaces (e
...
, as
function arguments; §7
...
3, §12
...
2) because the implicit conversion to pointer is the root cause of
many common errors in C code and C-style C++ code
...
2
...
That’s most easily and
most reliably done by having the lifetime of the free-store array controlled by a resource handle
(e
...
, string (§19
...
3), vector (§13
...
2), or unique_ptr (§34
...
1))
...
Obviously, C programmers cannot follow
these pieces of advice because C lacks the ability to encapsulate arrays, but that doesn’t make the
advice bad in the context of C++
...
That’s the way
C stores strings, so a zero-terminated array of char is often called a C-style string
...
3
...
g
...
4) rely on it
...


7
...
1 Array Initializers
An array can be initialized by a list of values
...
Consequently, v1 and v2 are of type int[4] and
char[4], respectively
...
For example:
char v3[2] = { 'a', 'b', 0 };
char v4[3] = { 'a', 'b', 0 };

// error : too many initializers
// OK

If the initializer supplies too few elements for an array, 0 is used for the rest
...
You cannot initialize one array with another (not
even of exactly the same type), and there is no array assignment:
int v6[8] = v5; // error: can’t copy an array (cannot assign an int* to an array)
v6 = v5;
// error : no array assignment

Similarly, you can’t pass arrays by value
...
4
...
4
...
6, §34
...
2
...
5) instead
...
3
...


7
...
2 String Literals
A string literal is a character sequence enclosed within double quotes:
"this is a string"

A string literal contains one more character than it appears to have; it is terminated by the null character, '\0', with the value 0
...

In C and in older C++ code, you could assign a string literal to a non-const char∗:
void f()
{
char∗ p = "Plato";
p[4] = 'e';
}

// error, but accepted in pre-C++11-standard code
// error: assignment to const

It would obviously be unsafe to accept that assignment
...
Having string literals immutable is not only obvious but also allows implementations to do significant optimizations
in the way string literals are stored and accessed
...
For example:
const char∗ error_message(int i)
{
//
...
3
...

Whether two identical string literals are allocated as one array or as two is implementationdefined (§6
...
For example:
const char∗ p = "Heraclitus";
const char∗ q = "Heraclitus";
void g()
{
if (p == q) cout << "one!\n";
//
...

The empty string is written as a pair of adjacent double quotes, "", and has the type const
char[1]
...

The backslash convention for representing nongraphic characters (§6
...
3
...
This makes it possible to represent the double quote (") and the escape character
backslash (\) within a string
...

For example:
cout<<"beep at end of message\a\n";

The escape character, '\a', is the ASCII character BEL (also known as alert), which causes a sound
to be emitted
...
For example:
char alpha[] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";

The compiler will concatenate adjacent strings, so alpha could equivalently have been initialized by
the single string
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

It is possible to have the null character in a string, but most programs will not suspect that there are
characters after it
...
4
...
3
...
1 Raw Character Strings
To represent a backslash (\) or a double quote (") in a string literal, we have to precede it with a
backslash
...
However, if we need a lot of backslashes
and a lot of quotes in string literals, this simple technique becomes unmanageable
...
1
...
This is a convention shared by many programming languages, so we can’t just change it
...
Consider how to write the pattern representing two words separated by a
backslash (\):
string s = "\\w\\\\w";

// I hope I got that right

To prevent the frustration and errors caused by this clash of conventions, C++ provides raw string
literals
...
The initial R is there
to distinguish raw string literals from ordinary string literals
...
For example:
R"("quoted string")"

// the string is "quoted string"

So, how do we get the character sequence )" into a raw string literal? Fortunately, that’s a rare
problem, but "( and )" is only the default delimiter pair
...
For example:
R"∗∗∗("quoted string containing the usual terminator ("))")∗∗∗"
// "quoted string containing the usual terminator ("))"

The character sequence after the ) must be identical to the sequence before the (
...

Unless you work with regular expressions, raw string literals are probably just a curiosity (and
one more thing to learn), but regular expressions are useful and widely used
...
)∗\")|"

// Are the five backslashes correct or not?

With examples like that, even experts easily become confused, and raw string literals provide a significant service
...
For example:
string counts {R"(1
22
333)"};

is equivalent to
string x {"1\n22\n333"};

7
...
2
...
2
...
Its type is const
wchar_t[]
...
3
...
1) of
wide characters of type const wchar_t[]
...


Section 7
...
2
...
This sounds
excessive, but there are three major encodings of Unicode: UTF-8, UTF-16, and UTF-32
...
All three UTF encodings support all Unicode characters, so which you use depends on the system you need to fit into
...
g
...

UTF-8 is a variable-width encoding: common characters fit into 1 byte, less frequently used
characters (by some estimate of use) into 2 bytes, and rarer characters into 3 or 4 bytes
...
The various Latin alphabets, Greek, Cyrillic, Hebrew, Arabic, and more fit into 2 bytes
...

We can represent an ordinary English character string in a variety of ways
...

Obviously, the real purpose of Unicode strings is to be able to put Unicode characters into them
...
"

Printing that string appropriately gives you
The official vowels in Danish are: a, e, i, o, u, æ, ø, å and y
...
2
...
3) [Unicode,1996]
...
For example, u'0430' (Cyrillic lowercase letter ‘‘a’’) is the
2-byte hexadecimal value D0B0 in UTF-8, the 2-byte hexadecimal value 0403 in UTF-16, and the
4-byte hexadecimal value 00000403 in UTF-32
...

The order of the us and Rs and their cases are significant: RU and Ur are not valid string prefixes
...
4 Pointers into Arrays
In C++, pointers and arrays are closely related
...
For example:

180

Pointers, Arrays, and References

Chapter 7

int v[] = { 1, 2, 3, 4 };
int∗ p1 = v;
// pointer to initial element (implicit conversion)
int∗ p2 = &v[0];
// pointer to initial element
int∗ p3 = v+4;
// pointer to one-beyond-last element

or graphically:
p1

v:

p2

1

2

3

p3

4

Taking a pointer to the element one beyond the end of an array is guaranteed to work
...
5, §33
...
However, since such a pointer does not in fact point
to an element of the array, it may not be used for reading or writing
...
For example:
int∗ p4 = v−1; // before the beginning, undefined: don’t do it
int∗ p5 = v+7; // beyond the end, undefined: don’t do it

The implicit conversion of an array name to a pointer to the initial element of the array is extensively used in function calls in C-style code
...
h>

void f()
{
char v[] = "Annemarie";
char∗ p = v;
// implicit conversion of char[] to char*
strlen(p);
strlen(v);
// implicit conversion of char[] to char*
v = p;
// error: cannot assign to array
}

The same value is passed to the standard-library function strlen() in both calls
...
In other words, there is no way of declaring a function
so that the array v is copied when the function is called
...

The implicit conversion of the array argument to a pointer means that the size of the array is lost
to the called function
...
Like other C standard-library functions taking pointers to characters, strlen()
relies on zero to indicate end-of-string; strlen(p) returns the number of characters up to and not
including the terminating 0
...
The standard-library vector (§4
...
1, §13
...
4), array (§8
...
4, §34
...
1), and string (§4
...
These library types
give their number of elements as their size() without having to count elements each time
...
4
...
4
...
5, Chapter 32)
...
For example:
void fi(char v[])
{
for (int i = 0; v[i]!=0; ++i)
use(v[i]);
}
void fp(char v[])
{
for (char∗ p = v; ∗p!=0; ++p)
use(∗p);
}

The prefix ∗ operator dereferences a pointer so that ∗p is the character pointed to by p, and ++ increments the pointer so that it refers to the next element of the array
...
With modern compilers, identical code should be (and usually is) generated for both examples
...

Subscripting a built-in array is defined in terms of the pointer operations + and ∗
...
For example, 3["Texas"]=="Texas"[3]=='a'
...
These equivalences are pretty low-level and do not
hold for standard-library containers, such as array and vector
...
When an arithmetic operator is applied to a pointer p of type T∗, p is assumed
to point to an element of an array of objects of type T; p+1 points to the next element of that array,
and p−1 points to the previous element
...
For example:
template
int byte_diff(T∗ p, T∗ q)
{
return reinterpret_cast(q)−reinterpret_cast(p);
}
void diff_test()
{
int vi[10];
short vs[10];

182

Pointers, Arrays, and References

Chapter 7

cout << vi << ' ' << &vi[1] << ' ' << &vi[1]−&vi[0] << ' ' << byte_diff(&vi[0],&vi[1]) << '\n';
cout << vs << ' ' << &vs[1] << ' ' << &vs[1]−&vs[0] << ' ' << byte_diff(&vs[0],&vs[1]) << '\n';
}

This produced:
0x7fffaef0 0x7fffaef4 1 4
0x7fffaedc 0x7fffaede 1 2

The pointer values were printed using the default hexadecimal notation
...

Subtraction of pointers is defined only when both pointers point to elements of the same array
(although the language has no fast way of ensuring that is the case)
...
One can add an integer to a pointer or subtract an integer from a pointer; in both cases, the
result is a pointer value
...
For example:
void f()
{
int v1[10];
int v2[10];
int i1 = &v1[5]−&v1[3];
int i2 = &v1[5]−&v2[3];

// i1 = 2
// result undefined

int∗ p1 = v2+2;
int∗ p2 = v2−2;

// p1 = &v2[2]
// *p2 undefined

}

Complicated pointer arithmetic is usually unnecessary and best avoided
...

Arrays are not self-describing because the number of elements of an array is not guaranteed to
be stored with the array
...
For example:
void fp(char v[], int size)
{
for (int i=0; i!=size; ++i)
use(v[i]);
for (int x : v)
use(x);
const int N = 7;
char v2[N];
for (int i=0; i!=N; ++i)
use(v2[i]);
for (int x : v2)
use(x);
}

// hope that v has at least size elements
// error : range-for does not work for pointers

// range-for works for arrays of known size

Section 7
...
1

Navigating Arrays

183

This array concept is inherently low-level
...
2
...
2
...

Some C++ implementations offer optional range checking for arrays
...
If you are not using range checking for individual accesses, try to maintain a consistent policy of accessing elements only in well-defined ranges
...


7
...
2 Multidimensional Arrays
Multidimensional arrays are represented as arrays of arrays; a 3-by-5 array is declared like this:
int ma[3][5];

// 3 arrays with 5 ints each

We can initialize ma like this:
void init_ma()
{
for (int i = 0; i!=3; i++)
for (int j = 0; j!=5; j++)
ma[i][j] = 10∗i+j;
}

or graphically:
ma:

00 01 02 03 04 10 11 12 13 14 20 21 22 23 24

The array ma is simply 15 ints that we access as if it were 3 arrays of 5 ints
...
The dimensions 3
and 5 exist in the compiler source only
...
For example, we might print ma like this:
void print_ma()
{
for (int i = 0; i!=3; i++) {
for (int j = 0; j!=5; j++)
cout << ma[i][j] << '\t';
cout << '\n';
}
}

The comma notation used for array bounds in some languages cannot be used in C++ because the
comma (,) is a sequencing operator (§10
...
2)
...
For example:
int bad[3,5];
int good[3][5];
int ouch = good[1,4];
int nice = good[1][4];

// error: comma not allowed in constant expression
// 3 arrays with 5 ints each
// error: int initialized by int* (good[1,4] means good[4], which is an int*)

184

Pointers, Arrays, and References

Chapter 7

7
...
3 Passing Arrays
Arrays cannot directly be passed by value
...
For example:
void comp(double arg[10])
{
for (int i=0; i!=10; ++i)
arg[i]+=99;
}

// arg is a double*

void f()
{
double a1[10];
double a2[5];
double a3[100];
comp(a1);
comp(a2);
comp(a3);

// disaster!
// uses only the first 10 elements

};

This code looks sane, but it is not
...
Also, anyone who guessed that the array was passed by value will be disappointed:
the writes to arg[i] are writes directly to the elements of comp()’s argument, rather than to a copy
...
When used as a function argument, the first dimension of
an array is simply treated as a pointer
...
This implies
that if you want to pass a sequence of elements without losing size information, you should not
pass a built-in array
...

If you insist on using arrays directly, you will have to deal with bugs and confusion without getting noticeable advantages in return
...
If the dimensions are known at compile time, there is no problem:
void print_m35(int m[3][5])
{
for (int i = 0; i!=3; i++) {
for (int j = 0; j!=5; j++)
cout << m[i][j] << '\t';
cout << '\n';
}
}

Section 7
...
3

Passing Arrays

185

A matrix represented as a multidimensional array is passed as a pointer (rather than copied; §7
...

The first dimension of an array is irrelevant to finding the location of an element; it simply states
how many elements (here, 3) of the appropriate type (here, int[5]) are present
...
The first dimension can therefore be passed as an argument:
void print_mi5(int m[][5], int dim1)
{
for (int i = 0; i!=dim1; i++) {
for (int j = 0; j!=5; j++)
cout << m[i][j] << '\t';
cout << '\n';
}
}

When both dimensions need to be passed, the ‘‘obvious solution’’ does not work:
void print_mij(int m[][], int dim1, int dim2)
// doesn’t behave as most people would think
{
for (int i = 0; i!=dim1; i++) {
for (int j = 0; j!=dim2; j++)
cout << m[i][j] << '\t';
// sur prise!
cout << '\n';
}
}

Fortunately, the argument declaration m[][] is illegal because the second dimension of a multidimensional array must be known in order to find the location of an element
...
A correct solution is:
void print_mij(int∗ m, int dim1, int dim2)
{
for (int i = 0; i!=dim1; i++) {
for (int j = 0; j!=dim2; j++)
cout << m[i∗dim2+j] << '\t'; // obscure
cout << '\n';
}
}

The expression used for accessing the members in print_mij() is equivalent to the one the compiler
generates when it knows the last dimension
...
This kind of subtle and messy code is best hidden
...
In that way, you might ease the
task of the next programmer to touch the code
...
2
...
5
...

The standard vector (§31
...


7
...
2
...
4)
...
2
...

Basically, constexpr’s role is to enable and ensure compile-time evaluation, whereas const’s primary role is to specify immutability in interfaces
...

Many objects don’t have their values changed after initialization:
• Symbolic constants lead to more maintainable code than using literals directly in code
...

• Most function parameters are read but not written to
...
For example:
const int model = 90;
const int v[] = { 1, 2, 3, 4 };
const int x;

// model is a const
// v[i] is a const
// error : no initializer

Because an object declared const cannot be assigned to, it must be initialized
...
For example:
void g(const X∗ p)
{
// can’t modify *p here
}

Section 7
...

}

Pointers and const

187

// val can be modified here

When using a pointer, two objects are involved: the pointer itself and the object pointed to
...
To
declare a pointer itself, rather than the object pointed to, to be a constant, we use the declarator
operator ∗const instead of plain ∗
...
There is no const∗ declarator operator, so a const appearing before the ∗ is taken to be part of the base type
...
’’
An object that is a constant when accessed through one pointer may be variable when accessed
in other ways
...
By declaring a pointer argument
const, the function is prohibited from modifying the object pointed to
...
The second version is used for mutable strings
...
However, the address of a constant cannot be assigned to an unrestricted pointer
because this would allow the object’s value to be changed
...
2
...
5)
...
6 Pointers and Ownership
A resource is something that has to be acquired and later released (§5
...
Memory acquired by new
and released by delete (§11
...
2) are examples of resources where the most direct handle to the resource is a pointer
...
Consider:
void confused(int∗ p)
{
// delete p?
}
int global {7};
void f()
{
X∗ pn = new int{7};
int i {7};
int q = &i;
confused(pn);
confused(q);
confused(&global);
}

If confused() deletes p the program will seriously misbehave for the second two calls because we
may not delete objects not allocated by new (§11
...
If confused() does not delete p the program
leaks (§11
...
1)
...

It is usually a good idea to immediately place a pointer that represents ownership in a resource
handle class, such as vector, string, and unique_ptr
...
Chapter 13 discusses
resource management in greater detail
...
7

References

189

7
...
The type of the pointer determines what can
be done to the data through the pointer
...
m
...

• We must be more careful when using pointers than when using an object directly: a pointer
may be a nullptr or point to an object that wasn’t the one we expected
...
Worse, managing pointer variables with varying values and protecting code against the possibility of nullptr can be a significant burden
...
The language mechanism addressing these problems is
called a reference
...

• A reference always refers to the object to which it was initialized
...
7
...

A reference is an alternative name for an object, an alias
...
For example:
template
class vector {
T∗ elem;
//
...


// pass element to be added by reference

};
void f(const vector& v)
{
double d1 = v[1];
// copy the value of the double referred to by v
...
operator[](2)
v
...


190

Pointers, Arrays, and References

Chapter 7

To reflect the lvalue/rvalue and const/non-const distinctions, there are three kinds of references:
• lvalue references: to refer to objects whose value we want to change
• const references: to refer to objects whose value we do not want to change (e
...
, a constant)
• rvalue references: to refer to objects whose value we do not need to preserve after we have
used it (e
...
, a temporary)
Collectively, they are called references
...


7
...
1 Lvalue References
In a type name, the notation X& means ‘‘reference to X
...
For example:
void f()
{
int var = 1;
int& r {var};
int x = r;
r = 2;

// r and var now refer to the same int
// x becomes 1
// var becomes 2

}

To ensure that a reference is a name for something (that is, that it is bound to an object), we must
initialize the reference
...
Despite appearances, no operator operates on a reference
...
Consequently, the value of a reference cannot be changed after initialization; it always
refers to the object it was initialized to denote
...
Thus, we cannot have a pointer to a reference
...
In that sense, a reference is not an object
...
It doesn’t do much harm to think about references that way, as long as one remembers that a reference isn’t an object that can be manipulated the way a pointer is:

Section 7
...
1

Lvalue References

pp:

191

&ii
rr:

ii:

1

In some cases, the compiler can optimize away a reference so that there is no object representing
that reference at run time
...
4)
...

The initializer for a const T& need not be an lvalue or even of type T
...
5)
...

[3] Finally, this temporary variable is used as the value of the initializer
...

References to variables and references to constants are distinguished because introducing a temporary for a variable would have been highly error-prone; an assignment to the variable would
become an assignment to the – soon-to-disappear – temporary
...
2
...

A reference can be used to specify a function argument so that the function can change the
value of an object passed to it
...
To keep a program readable, it is often best to
avoid functions that modify their arguments
...
Consequently, ‘‘plain’’ reference arguments should be used only where the name of
the function gives a strong hint that the reference argument is modified
...
This is mostly used to define functions that can be
used on both the left-hand and right-hand sides of an assignment
...
For
example:
template
class Map {
// a simple map class
public:
V& operator[](const K& v);
// return the value corresponding to the key v
pair∗ begin() { return &elem[0]; }
pair∗ end() { return &elem[0]+elem
...
4
...
4
...
first)
return x
...
push_back({k,V{}});
return elem
...
second;

// add pair at end (§4
...
2)
// return the (default) value of the new element

}

I pass the key argument, k, by reference because it might be of a type that is expensive to copy
...

I use a const reference for k because I don’t want to modify it and because I might want to use a literal or a temporary object as an argument
...
For example:

Section 7
...
1

Lvalue References

193

int main() // count the number of occurrences of each word on input
{
Map buf;
for (string s; cin>>s;) ++buf[s];
for (const auto& x : buf)
cout << x
...
second << '\n';
}

Each time around, the input loop reads one word from the standard input stream cin into the string s
(§4
...
2) and then updates the counter associated with it
...
For example, given the input
aa bb bb aa aa bb aa aa

this program will produce
aa: 5
bb: 3

The range- for loop works for this because
standard-library map
...
7
...

• A const lvalue reference refers to a constant, which is immutable from the point of view of
the user of the reference
...

We want to know if a reference refers to a temporary, because if it does, we can sometimes turn an
expensive copy operation into a cheap move operation (§3
...
2, §17
...
5
...
An object (such as
a string or a list) that is represented by a small descriptor pointing to a potentially huge amount of
information can be simply and cheaply moved if we know that the source isn’t going to be used
again
...
3
...

An rvalue reference can bind to an rvalue, but not to an lvalue
...
For example:
string var {"Cambridge"};
string f();
string& r1 {var};
string& r2 {f()};
string& r3 {"Princeton"};

// lvalue reference, bind r1 to var (an lvalue)
// lvalue reference, error : f() is an rvalue
// lvalue reference, error : cannot bind to temporar y

194

Pointers, Arrays, and References

string&& rr1 {f()};
string&& rr2 {var};
string&& rr3 {"Oxford"};

Chapter 7

// rvalue reference, fine: bind rr1 to rvalue (a temporar y)
// rvalue reference, error : var is an lvalue
// rr3 refers to a temporar y holding "Oxford"

const string cr1& {"Harvard"}; // OK: make temporar y and bind to cr1

The && declarator operator means ‘‘rvalue reference
...
Both a
const lvalue reference and an rvalue reference can bind to an rvalue
...

• We use a const lvalue reference to prevent modification of an argument
...
For example:
string f(string&& s)
{
if (s
...
Consider:
template
swap(T& a, T& b)
// "old-style swap"
{
T tmp {a}; // now we have two copies of a
a = b;
// now we have two copies of b
b = tmp; // now we have two copies of tmp (aka a)
}

If T is a type for which it can be expensive to copy elements, such as string and vector, this swap()
becomes an expensive operation
...
We can tell that to the compiler:
template
void swap(T& a, T& b)
// "perfect swap" (almost)
{
T tmp {static_cast(a)}; // the initialization may write to a
a = static_cast(b);
// the assignment may write to b
b = static_cast(tmp); // the assignment may write to tmp
}

The result value of static_cast(x) is an rvalue of type T&& for x
...
In particular, if a type T has a move constructor (§3
...
2, §17
...
2) or a move assignment, it will be used
...
7
...

vector(const vector& r); // copy constructor (copy r’s representation)
vector(vector&& r);
// move constructor ("steal" representation from r)
};
vector s;
vector s2 {s};
vector s3 {s+"tail");

// s is an lvalue, so use copy constructor
// s+"tail" is an rvalue so pick move constructor

The use of static_cast in swap() is a bit verbose and slightly prone to mistyping, so the standard
library provides a move() function: move(x) means static_cast(x) where X is the type of x
...

Since move(x) does not move x (it simply produces an rvalue reference to x), it would have been
better if move() had been called rval(), but by now move() has been used for years
...
Consider:
void f(vector& v)
{
swap(v,vector{1,2,3});
//
...
A solution is to augment it by two overloads:
template void swap(T&& a, T& b);
template void swap(T& a, T&& b)

Our example will be handled by that last version of swap()
...
(§31
...
3) to handle the most
common cases of rvalue arguments to swap():
void f(string& s, vector& v)
{
s
...
capacity()==s
...
capacity()==s
...
clear();
swap(v
...
5
...
1, §35
...
1)
...
3
...

Also, their operations that insert new elements, such as insert() and push_back(), have versions that
take rvalue references
...
7
...
But what kind of reference? Lvalue reference or rvalue
reference? Consider:
using rr_i = int&&;
using lr_i = int&;
using rr_rr_i = rr_i&&;
using lr_rr_i = rr_i&;
using rr_lr_i = lr_i&&;
using lr_lr_i = lr_i&;

// ‘‘int && &&’’ is an int&&
// ‘‘int && &’’ is an int&
// ‘‘int & &&’’ is an int&
// ‘‘int & &’’ is an int&

In other words, lvalue reference always wins
...
This is sometimes known as reference
collapse
...
4
...
5) or a template type
argument (§23
...
2
...


7
...
4 Pointers and References
Pointers and references are two mechanisms for referring to an object from different places in a
program without copying
...

If you need to change which object to refer to, use a pointer
...
1
...
For example:

Section 7
...
4

Pointers and References

197

void fp(char∗ p)
{
while (∗p)
cout << ++∗p;
}
void fr(char& r)
{
while (r)
cout << ++r;

// oops: increments the char referred to, not the reference
// near-infinite loop!

}
void fr2(char& r)
{
char∗ p = &r;
// get a pointer to the object referred to
while (∗p)
cout << ++∗p;
}

Conversely, if you want to be sure that a name always refers to the same object, use a reference
...

};

// Proxy refers to the object with which it is initialized

template class Handle { // Handle refers to its current object
T∗ m;
public:
Proxy(T∗ mm) :m{mm} {}
void rebind(T∗ mm) { m = mm; }
//
...
1) on something that refers to an
object, use a reference:
Matrix operator+(const Matrix&, const Matrix&);
Matrix operator−(const Matrix∗, const Matrix∗);

// OK
// error : no user-defined type argument

Matrix y, z;
//
...
2
...


198

Pointers, Arrays, and References

Chapter 7

If you want a collection of something that refers to an object, you must use a pointer:
int x, y;
string& a1[] = {x, y};
string∗ a2[] = {&x, &y};
vector s1 = {x , y};
vector s2 = {&x, &y};

// error : array of references
// OK
// error : vector of references
// OK

Once we leave the cases where C++ leaves no choice for the programmer, we enter the domain of
aesthetics
...

If you need a notion of ‘‘no value,’’ pointers offer nullptr
...
For example:
void fp(X∗ p)
{
if (p == nullptr) {
// no value
}
else {
// use *p
}
}
void fr(X& r) // common style
{
// assume that r is valid and use it
}

If you really want to, you can construct and check for a ‘‘null reference’’ for a particular type:
void fr2(X& r)
{
if (&r == &nullX) {
// no value
}
else {
// use r
}
}

// or maybe r==nullX

Obviously, you need to have suitably defined nullX
...
A programmer is allowed to assume that a reference is valid
...
For example:
char∗ ident(char ∗ p) { return p; }
char& r {∗ident(nullptr)}; // invalid code

This code is not valid C++ code
...


Section 7
...
8 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]
[14]

Keep use of pointers simple and straightforward; §7
...
1
...
4
...
4
...

Avoid multidimensional arrays; define suitable containers instead; §7
...
2
...
2
...

Use containers (e
...
, vector, array, and valarray) rather than built-in (C-style) arrays; §7
...
1
...
4
...
3
...
1
...
7
...

Use rvalue references (only) for forwarding and move semantics; §7
...
2
...
6
...
2
...

Use const pointers and const references to express immutability in interfaces; §7
...

Prefer references to pointers as arguments, except where ‘‘no object’’ is a reasonable option;
§7
...
4
...

– The people








Introduction
Structures
struct Layout; struct Names; Structures and Classes; Structures and Arrays; Type Equivalence; Plain Old Data; Fields
Unions
Unions and Classes; Anonymous unions
Enumerations
enum classes; Plain enums; Unnamed enums
Advice

8
...
This chapter introduces the three most primitive variants of the notion of a user-defined type:
• A struct (a structure) is a sequence of elements (called members) of arbitrary types
...

• An enum (an enumeration) is a type with a set of named constants (called enumerators)
...

Variants of these kinds of simple types have existed since the earliest days of C++
...

The notion of a struct as described here is a simple form of a class (§3
...


202

Structures, Unions, and Enumerations

Chapter 8

8
...
In its simplest form, a struct is an aggregate
of elements of arbitrary types
...
Note the terminating semicolon
...
(dot) operator
...
name = "Jim Dandy";
jd
...
3
...
For example:
Address jd = {
"Jim Dandy",
61, "South St",
"New Providence",
{'N','J'}, "07974"
};

Note that jd
...
Strings are terminated by a zero character, '\0', so "NJ" has three characters – one more than will fit into jd
...
I deliberately use rather
low-level types for the members to illustrate how that can be done and what kinds of problems it
can cause
...

For example:
void print_addr(Address∗ p)
{
cout << p−>name << '\n'
<< p−>number << ' ' << p−>street << '\n'
<< p−>town << '\n'
<< p−>state[0] << p−>state[1] << ' ' << p−>zip << '\n';
}

When p is a pointer, p−>m is equivalent to (∗p)
...


Section 8
...


203

(struct member

void print_addr2(const Address& r)
{
cout << r
...
number << ' ' << r
...
town << '\n'
<< r
...
state[1] << ' ' << r
...
2
...
For example:
Address current;
Address set_current(Address next)
{
address prev = current;
current = next;
return prev;
}

Other plausible operations, such as comparison (== and !=), are not available by default
...
2
...
1, Chapter 18)
...
2
...
For example, we might store
primitive equipment readout in a structure like this:
struct Readout {
char hour;
int value;
char seq;
};

// [0:23]
// sequence mark ['a':'z']

You could imagine the members of a Readout object laid out in memory like this:
hour: value:

seq:

Members are allocated in memory in declaration order, so the address of hour must be less than the
address of value
...
2
...

However, the size of an object of a struct is not necessarily the sum of the sizes of its members
...
For example, integers are often allocated on word boundaries
...
2
...
This leads to ‘‘holes’’ in the structures
...

You can minimize wasted space by simply ordering members by size (largest member first)
...
The
reason is that we need to maintain alignment when we put two objects next to each other, say, in an
array of Readouts
...

It is usually best to order members for readability and sort them by size only if there is a
demonstrated need to optimize
...
e
...
5)
...
2
...
For example:
struct Link {
Link∗ previous;
Link∗ successor;
};

However, it is not possible to declare new objects of a struct until its complete declaration has been
seen
...
To allow two (or

Section 8
...
2

struct

Names

205

more) structs to refer to each other, we can declare a name to be the name of a struct
...

The name of a struct can be used before the type is defined as long as that use does not require
the name of a member or the size of the structure to be known
...
For example:
struct S; // ‘‘S’’ is the name of some type
extern S a;
S f();
void g(S);
S∗ h(S∗);

However, many such declarations cannot be used unless the type S is defined:
void k(S∗ p)
{
S a;

// error: S not defined; size needed to allocate

f();
g(a);
p−>m = 7;

// error: S not defined; size needed to return value
// error: S not defined; size needed to pass argument
// error: S not defined; member name not known

S∗ q = h(p);
q−>m = 7;

// ok: pointers can be allocated and passed
// error: S not defined; member name not known

}

For reasons that reach into the prehistory of C, it is possible to declare a struct and a non-struct with
the same name in the same scope
...
*/ };
int stat(char∗ name, struct stat∗ buf);

In that case, the plain name (stat) is the name of the non-struct, and the struct must be referred to
with the prefix struct
...
3), and enum (§8
...
However, it is best not to overload names to make such explicit disambiguation necessary
...
2
...
So, a struct can have member
functions (§2
...
2, Chapter 16)
...
For example:
struct Points {
vector elem;// must contain at least one Point
Points(Point p0) { elem
...
push_back(p0); elem
...

};
Points x0;
Points x1{ {100,200} };
Points x1{ {100,200}, {300,400} };

// error : no default constructor
// one Point
// two Points

You do not need to define a constructor simply to initialize members in order
...
3
...
1)
// default construction: {{},{}}; that is {0
...
4
...
2, §13
...
For example:
struct Address {
string name;
int number;
string street;
string town;
char state[2];
char zip[5];

// "Jim Dandy"
// 61
// "South St"
// "New Providence"
// ’N’ ’J’
// 07974

Address(const string n, int nu, const string& s, const string& t, const string& st, int z);
};

Here, I added a constructor to ensure that every member was initialized and to allow me to use a
string and an int for the postal code, rather than fiddling with individual characters
...
2
...
1)

The Address constructor might be defined like this:

Section 8
...
3

Structures and Classes

207

Address::Address(const string& n, int nu, const string& s, const string& t, const string& st, int z)
// validate postal code
:name{n},
number{nu},
street{s},
town{t}
{
if (st
...
4
...
str()};
switch (zi
...
check that the code makes sense
...
2
...
For example:
struct Point {
int x,y
};
Point points[3] {{1,2},{3,4},{5,6}};
int x2 = points[2]
...
elem[2]
...
For
example:

208

Structures, Unions, and Enumerations

Chapter 8

Array shift(Array a, Point p)
{
for (int i=0; i!=3; ++i) {
a
...
x += p
...
elem[i]
...
y;
}
return a;
}
Array ax = shift(points2,{10,20});

The notation for Array is a bit primitive: Why i!=3? Why keep repeating
...
2
...
2
...

};

This array is a template to allow arbitrary numbers of elements of arbitrary types
...
5
...
1) and const objects (§16
...
9
...
Using array,
we can now write:
struct Point {
int x,y
};
using Array = array; // array of 3 Points
Array points {{1,2},{3,4},{5,6}};
int x2 = points[2]
...
y;

Section 8
...
4

Structures and Arrays

209

Array shift(Array a, Point p)
{
for (int i=0; i!=a
...
x += p
...
y += p
...
) and does not implicitly convert to a pointer to an individual element:
ostream& operator<<(ostream& os, Point p)
{
cout << '{' << p[i]
...
y << '}';
}
void print(Point a[],int s) // must specify number of elements
{
for (int i=0; i!=s; ++i)
cout << a[i] << '\n';
}
template
void print(array& a)
{
for (int i=0; i!=a
...
2
...
For example:
struct S1 { int a; };
struct S2 { int a; };
S1

and S2 are two different types, so:
S1 x;
S2 y = x; // error : type mismatch

A struct is also a different type from a type used as a member
...
2
...


8
...
6 Plain Old Data
Sometimes, we want to treat an object as just ‘‘plain old data’’ (a contiguous sequence of bytes in
memory) and not worry about more advanced semantic notions, such as run-time polymorphism
(§3
...
3, §20
...
2), user-defined copy semantics (§3
...
5), etc
...
For example, copying a 100-element array using 100 calls of a copy constructor is unlikely to be as fast as
calling std::memcpy(), which typically simply uses a block-move machine instruction
...
Such ‘‘tricks’’
are not uncommon, and are important, in implementations of containers, such as vector, and in lowlevel I/O routines
...

So, a POD (‘‘Plain Old Data’’) is an object that can be manipulated as ‘‘just data’’ without worrying about complications of class layouts or user-defined semantics for construction, copy, and
move
...
*/ };
struct S6 : S1 { };
struct S7 : S0 { int b; };
struct S8 : S1 { int b; };
struct S9 : S0, S1 {};

// a POD
// a POD
// not a POD (no default constructor)
// a POD (user-defined default constructor)
// a POD
// not a POD (has a virtual function)

// a POD
// a POD
// not a POD (data in both S1 and S8)
// a POD

For us to manipulate an object as ‘‘just data’’ (as a POD), the object must
• not have a complicated layout (e
...
, with a vptr; (§3
...
3, §20
...
2),
• not have nonstandard (user-defined) copy semantics, and
• have a trivial default constructor
...
2
...
Formally (§iso
...
9, §iso
...

A related concept is a trivial type, which is a type with
• a trivial default constructor and
• trivial copy and move operations
Informally, a default constructor is trivial if it does not need to do any work (use =default if you
need to define one §17
...
1)
...
2
...
3
...
3
...
7),
• has multiple access specifiers for non-static data members (§20
...

Basically, a standard layout type is one that has a layout with an obvious equivalent in C and is in
the union of what common C++ Application Binary Interfaces (ABIs) can handle
...
2
...
2, §17
...
Informally, a copy operation is trivial if it can be implemented as a bitwise copy
...

• Its class has a virtual function
...

• Its class has a base or a member that is not trivial
...
Also, an array of trivially
copyable objects is trivially copyable and an array of standard layout objects has standard layout
...
I could do that by only calling mycopy() for
PODs, but that’s error-prone: if I use mycopy() can I rely on a maintainer of the code to remember
never to call mycopy() for non-PODs? Realistically, I cannot
...
Anyway, here is the general
and optimized code:

212

Structures, Unions, and Enumerations

Chapter 8

template
void mycopy(T∗ to, const T∗ from, int count)
{
if (is_pod::value)
memcpy(to,from,count∗sizeof(T));
else
for (int i=0; i!=count; ++i)
to[i]=from[i];
}

The is_pod is a standard-library type property predicate (§35
...
1) defined in allowing
us to ask the question ‘‘Is T a POD?’’ in our code
...

Note that adding or subtracting non-default constructors does not affect layout or performance
(that was not true in C++98)
...
3
...
9) and try to think about their implications to programmers and compiler
writers
...


8
...
7 Fields
It seems extravagant to use a whole byte (a char or a bool) to represent a binary variable – for example, an on/off switch – but a char is the smallest object that can be independently allocated and
addressed in C++ (§7
...
It is possible, however, to bundle several such tiny variables together as
fields in a struct
...
A member is defined to be a field by specifying
the number of bits it is to occupy
...
They do not affect the meaning of
the named fields, but they can be used to make the layout better in some machine-dependent way:
struct PPN {
// R6000 Physical Page Number
unsigned int PFN : 22; // Page Frame Number
int : 3;
// unused
unsigned int CCA : 3;
// Cache Coherency Algorithm
bool nonreachable : 1;
bool dirty : 1;
bool valid : 1;
bool global : 1;
};

This example also illustrates the other main use of fields: to name parts of an externally imposed
layout
...
2
...
It is not possible to take the
address of a field
...
Note that a
bool field really can be represented by a single bit
...


Section 8
...
7

Fields

213

if (p−>dirty) { // contents changed
// copy to disk
p−>dirty = 0;
}
}

Surprisingly, using fields to pack several variables into a single byte does not necessarily save
space
...
Programs have been known to shrink significantly when binary variables were
converted from bit-fields to characters! Furthermore, it is typically much faster to access a char or
an int than to access a field
...
1
...


8
...
Naturally, a union can hold a value for only one
member at a time
...

}

The members s and i can never be used at the same time, so space is wasted
...
s if t==str; use v
...
s;
//
...
3
...

Unions are sometimes misused for ‘‘type conversion
...
For example, the following ‘‘converts’’ an int to an int∗ simply by assuming bitwise
equivalence:
union Fudge {
int i;
int∗ p;
};
int∗ cheat(int i)
{
Fudge a;
a
...
p;
}

// bad use

This is not really a conversion at all
...
Such use of a union is dangerous and nonportable
...
5
...
For example:
int∗ cheat2(int i)
{
return reinterpret_cast(i);
}

// obviously ugly and dangerous

Here, at least the compiler has a chance to warn you if the sizes of objects are different and such
code stands out like the sore thumb it is
...
However, most programs don’t improve much from the use of unions and unions are rather error-prone
...


Section 8
...
1

Unions and Classes

215

8
...
1 Unions and Classes
Many nontrivial unions have a member that is much larger than the most frequently used members
...
This waste
can often be eliminated by using a set of derived classes (§3
...
2, Chapter 20) instead of a union
...
2) which in turn is a kind of a class (Chapter 16)
...

[2] A union cannot have members of reference type
...

[4] If a union has a member with a user-defined constructor, a copy operation, a move operation, or a destructor, then that special function is deleted (§3
...
4, §17
...
4) for that union;
that is, it cannot be used for an object of the union type
...
4
...

[6] A union cannot be used as a base class
...
The latter
is important because the use of unions is often an optimization and we won’t want ‘‘hidden costs’’
imposed to compromise that
...
) from a union with a member that has a constructor (etc
...
For example, since Entry has no member with constructors, destructors, or assignments, we can create and copy Entrys freely
...
For example:
void f2(U x)
{
U u;
U u2 = x;
u
...
m3;
return;
}

// error : which default constructor?
// error : which copy constructor?
// assign to int member
// disaster : read from string member
// error : which destructors are called for x, u, and u2?

It’s illegal to write one member and then read another, but people do that nevertheless (usually by
mistake)
...
It is

216

Structures, Unions, and Enumerations

Chapter 8

fortunate that U won’t compile
...
3
...
If
desired, such a class can also prevent the error of writing one member and then reading another
...
If so, this initializer will
be used for default initialization
...
p == ""
// x2
...
3
...
3):

union,

consider a

class Entry2 { // two alternative representations represented as a union
private:
enum class Tag { number, text };
Tag type; // discriminant
union { // representation
int i;
string s; // string has default constructor, copy operations, and destructor
};
public:
struct Bad_entry { };
// used for exceptions
string name;
˜Entry2();
Entry2& operator=(const Entry2&);
Entry2(const Entry2&);
//
...

};

I’m not a fan of get/set functions, but in this case we really need to perform a nontrivial user-specified action on each access
...
That happens to be my favorite among the many naming conventions
...
3
...
Such a union
is often called a tagged union or a discriminated union
...
˜string();
type = Tag::number;
}
i = n;
}

// explicitly destroy string (§11
...
4)

void Entry2::set_text(const string& ss)
{
if (type==Tag::text)
s = ss;
else {
new(&s) string{ss};
// placement new: explicitly construct string (§11
...
4)
type = Tag::text;
}
}

The use of a union forces us to use otherwise obscure and low-level language facilities (explicit
construction and destruction) to manage the lifetime of the union elements
...

Note that the union in the declaration of Entry2 is not named
...
An anonymous union is an object, not a type, and its members can be accessed without
mentioning an object name
...

Entry2 has a member of a type with a user-defined assignment operator, string, so Entry2’s
assignment operator is deleted (§3
...
4, §17
...
4)
...


Assignment combines the complexities of reading and writing but is otherwise
logically similar to the access functions:
Entry2& Entry2::operator=(const Entry2& e) // necessar y because of the string variant
{
if (type==Tag::text && e
...
s;
// usual string assignment
return ∗this;
}
if (type==Tag::text) s
...
2
...
type) {
case Tag::number:
i = e
...
s); // placement new: explicit construct (§11
...
4)
type = e
...
We need at least a constructor or two to establish the correspondence between the type tag and a value
...
˜string(); // explicit destroy (§11
...
4)
}

8
...
7
...

Some of an enumeration’s possible values are named and called enumerators
...
‘‘An enumeration’’ is colloquially shortened to ‘‘an enum
...
g
...


Section 8
...
1

enum classes

219

8
...
1 enum classes
An enum class is a scoped and strongly typed enumeration
...
*/ }
if (x == red) { /*
...
*/ }
if (x == Traffic_light::red) { /*
...

An enumeration is represented by some integer type and each enumerator by some integer
value
...
The underlying type
must be one of the signed or unsigned integer types (§6
...
4); the default is int
...
Here, we get:
static_cast(Warning::green)==0
static_cast(Warning::yellow)==1
static_cast(Warning::orange)==2
static_cast(Warning::red)==3

Declaring a variable Warning instead of plain
as to the intended use
...

An enumerator can be initialized by a constant expression (§10
...
2
...
For
example:
enum class Printer_flags {
acknowledge=1,
paper_empty=2,
busy=4,
out_of_black=8,
out_of_color=16,
//
};

The values for the Printer_flags enumerators are chosen so that they can be combined by bitwise
operations
...
2
...
1,
Chapter 18)
...

Given these definitions of | and & for Printer_flags, we can write:
void try_to_print(Printer_flags x)
{
if (x&Printer_flags::acknowledge) {
//
...

}
else if (x&(Printer_flags::out_of_black|Printer_flags::out_of_color)) {
// either we are out of black or we are out of color
//
...

}

Section 8
...
1

enum classes

221

I defined operator|() and operator&() to be constexpr functions (§10
...
1
...
For example:
void g(Printer_flags x)
{
switch (x) {
case Printer_flags::acknowledge:
//
...

break;
case Printer_flags::out_of_black:
//
...

break;
case Printer_flags::out_of_black&Printer_flags::out_of_color:
// we are out of black *and* out of color
//
...

}

It is possible to declare an enum class without defining it (§6
...
For example:
enum class Color_code : char;
void foobar(Color_code∗ p);
//
...
The result of such a
conversion is undefined unless the value is within the range of the enumeration’s underlying type
...


222

Structures, Unions, and Enumerations

Chapter 8

Each enumerator has an integer value
...
For example:
int i = static_cast(Flag::y);
char c = static_cast(Flag::e);

// i becomes 2
// c becomes 8

The notion of a range of values for an enumeration differs from the enumeration notion in the Pascal family of languages
...
g
...

The sizeof an enum class is the sizeof of its underlying type
...


8
...
2 Plain enums
A ‘‘plain enum’’ is roughly what C++ offered before the enum classes were introduced, so you’ll
find them in lots of C and C++98-style code
...
Consider the examples from §8
...
1 with the ‘‘class’’ removed:
enum Traffic_light { red, yellow, green };
enum Warning { green, yellow, orange, red }; // fire alert levels
// error: two definitions of yellow (to the same value)
// error: two definitions of red (to different values)
Warning a1 = 7;
int a2 = green;
int a3 = Warning::green;
Warning a4 = Warning::green;

// error : no int->Warning conversion
// OK: green is in scope and converts to int
// OK: Warning->int conversion
// OK

void f(Traffic_light x)
{
if (x == 9) { /*
...
*/ }
if (x == Warning::red) { /*
...
*/ }
}

// OK (but Traffic_light doesn’t have a 9)
// error : two reds in scope
// OK (Ouch!)
// OK

We were ‘‘lucky’’ that defining red in two plain enumerations in a single scope saved us from hardto-spot errors
...
4
...
*/ }
if (x == Warning::red) { /*
...
*/ }
}

223

// OK (ouch!)
// OK (ouch!)
// error : red is not a Traffic_light value

The compiler accepts the x==red, which is almost certainly a bug
...

You can specify the underlying type of a plain enumeration, just as you can for enum classes
...
For example:
enum Traffic_light : char { tl_red, tl_yellow, tl_green };

// underlying type is char

enum Color_code : char;
// declaration
void foobar(Color_code∗ p); // use of declaration
//
...
If there are negative enumerators, the range is [-2 :2 -1]
...
For example:
enum E1 { dark, light };
// range 0:1
enum E2 { a = 3, b = 9 };
// range 0:15
enum E3 { min = −10, max = 1000000 }; // range -1048576:1048575

The rule for explicit conversion of an integer to a plain enum is the same as for the class enum
except that when there is no explicit underlying type, the result of such a conversion is undefined
unless the value is within the range of the enumeration
...
The
sizeof an enumeration is the sizeof its underlying type
...
For example, sizeof(e1) could be 1 or
maybe 4 but not 8 on a machine where sizeof(int)==4
...
4
...
For example:
enum { arrow_up=1, arrow_down, arrow_sideways };

We use that when all we need is a set of integer constants, rather than a type to use for variables
...
5 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]

When compactness of data is important, lay out structure data members with larger members
before smaller ones; §8
...
1
...
2
...

Don’t naively try to optimize memory consumption by packing several values into a single
byte; §8
...
7
...
3
...
4
...
4
...
4
...


9
Statements
A programmer is a machine
for turning caffeine into code
...
1 Introduction
C++ offers a conventional and flexible set of statements
...
Note that a declaration is a statement and
that an expression becomes a statement when you add a semicolon at its end
...
Instead, statements are used to specify
the order of execution
...
A compiler may reorder code
to improve performance as long as the result is identical to that of the simple order of execution
...
2 Statement Summary
Here is a summary of C++ statements:
statement:
declaration
expressionopt ;
{ statement-listopt }
try { statement-listopt } handler-list
case constant-expression :
default : statement
break ;
continue ;
return

statement

expressionopt ;

identifier ;
identifier : statement

goto

selection-statement
iteration-statement
selection-statement:
if ( condition ) statement
if ( condition ) statement else statement
switch ( condition ) statement
iteration-statement:
while ( condition ) statement
do statement while ( expression ) ;
for ( for-init-statement conditionopt ; expressionopt ) statement
for ( for-init-declaration : expression ) statement
statement-list:
statement statement-listopt
condition:
expression
type-specifier declarator = expression
type-specifier declarator { expression }
handler-list:
handler handler-listopt
handler:
catch (

exception-declaration ) { statement-listopt }

A semicolon is by itself a statement, the empty statement
...
2

Statement Summary

227

A (possibly empty) sequence of statements within ‘‘curly braces’’ (i
...
, { and }) is called a block
or a compound statement
...
3
...

A declaration is a statement and there is no assignment statement or procedure-call statement;
assignments and function calls are expressions
...
Note that both end
with a semicolon
...

The statements for handling exceptions, try-blocks, are described in §13
...


9
...
Unless a variable is declared static, its initializer is executed whenever
the thread of control passes through the declaration (see also §6
...
2)
...
4
...
5
...
There is rarely a reason to introduce a variable before there is a value for it to hold
...
size()<=i)
error("bad index");
string s = v[i];
if (s == p) {
//
...

}

The ability to place declarations after executable code is essential for many constants and for single-assignment styles of programming where a value of an object is not changed after initialization
...
For example:
void use()
{
string s1;
s1 = "The best is the enemy of the good
...

}

This requests a default initialization (to the empty string) followed by an assignment
...
Input variables are among the few reasonable examples of that:
void input()
{
int buf[max];
int count = 0;
for (int i; cin>>i;) {
if (i<0) error("unexpected negative value");
if (count==max) error("buffer overflow");
buf[count++] = i;
}
//
...
Often,
push_back() (§3
...
1
...
6, §31
...
6) provides a better solution to such examples
...
4 Selection Statements
A value can be tested by either an if-statement or a switch-statement:
condition ) statement
condition ) statement else statement
switch ( condition ) statement
if (
if (

A condition is either an expression or a declaration (§9
...
3)
...
4
...
If a condition evaluates to something different
from a Boolean, it is – if possible – implicitly converted to a bool
...
For example, if x is an integer, then
if (x) //
...


For a pointer p,
if (p) //
...


Note that a ‘‘plain’’ enum can be implicitly converted to an integer and then to a
enum class cannot (§8
...
1)
...
4
...

if (y)
//
...

}

// OK
// error: no conversion to bool
// OK

The logical operators
&& ||

!

are most commonly used in conditions
...
For example,
if (p && 1count) //
...

For choosing between two alternatives each of which produces a value, a conditional expression
(§11
...
3) is a more direct expression of intent than an if-statement
...
In particular, it cannot be used
on another branch of an if-statement
...

}
else {
++x; // error: x is not in scope
}
++x;
// error: x is not in scope
}

A branch of an if-statement cannot be just a declaration
...
2)
...
4
...
The expression in the case
labels must be a constant expression of integral or enumeration type
...
For example:
void f(int i)
{
switch (i) {
case 2
...

case 2:
//
...

};

A switch-statement can alternatively be written as a set of if-statements
...
This makes the switch-statement
easier to read for nontrivial examples
...
Instead, a jump table can be used
...
4
...
Consider:
switch (val) {
// beware
case 1:
cout << "case 1\n";
case 2:
cout << "case 2\n";
default:
cout << "default: case not found\n";
}

Invoked with val==1, the output will greatly surprise the uninitiated:
case 1
case 2
default: case not found

It is a good idea to comment the (rare) cases in which a fall-through is intentional so that an uncommented fall-through can be assumed to be an error
...

}

A break is the most common way of terminating a case, but a return is often useful (§10
...
1)
...
One use is for the default to handle the most common case
...
However, there is one case where a default should not be used: if a switch is intended
to have one case for each enumerator of an enumeration
...
For example, this is almost certainly an error:
enum class Vessel { cup, glass, goblet, chalice };
void problematic(Vessel v)
{
switch (v) {
case Vessel::cup:
case Vessel::glass:
case Vessel::goblet:
}
}

/*
...
*/
/*
...

Testing for an ‘‘impossible’’ enumerator value is best done separately
...
4
...
1 Declarations in Cases
It is possible, and common, to declare variables within the block of a switch-statement
...
For example:
void f(int i)
{
switch (i) {
case 0:
int x;
int y = 3;
string s;
case 1:
++x;
++y;
s = "nasty!";
}
}

// uninitialized
// error: declaration can be bypassed (explicitly initialized)
// error: declaration can be bypassed (implicitly initialized)
// error: use of uninitialized object

Here, if i==1, the thread of execution would bypass the initializations of y and s, so f() will not compile
...
However, its use is an error: we read an uninitialized variable
...
As
usual, avoid uninitialized variables (§6
...
5
...

If we need a variable within a switch-statement, we can limit its scope by enclosing its declaration and its use in a block
...
2
...


9
...
3 Declarations in Conditions
To avoid accidental misuse of a variable, it is usually a good idea to introduce the variable into the
smallest scope possible
...
That way, one cannot get into trouble by using the variable
before its initial value is assigned
...
Consider:
if (double d = prim(true)) {
left /= d;
break;
}

Here, d is declared and initialized and the value of d after initialization is tested as the value of the
condition
...
For example, had there been an else-branch to the if-statement, d would be in
scope on both branches
...
4
...
However, this opens
the scope (literally) for the use of d before its initialization or after its intended useful life:
double d;
//
...

if (d = prim(true)) {
left /= d;
break;
}
//
...
0; // two unrelated uses of d

In addition to the logical benefits of declaring variables in conditions, doing so also yields the most
compact source code
...


9
...
Note that both end
with a semicolon
...

More complicated loops can be expressed as an algorithm plus a lambda expression (§11
...
2)
...
5
...
For example:
int sum(vector& v)
{
int s = 0;
for (int x : v)
s+=x;
return s;
}

234

Statements

Chapter 9

The for (int x : v) can be read as ‘‘for each element x in the range v’’ or just ‘‘for each x in v
...

The scope of the variable naming the element (here, x) is the for-statement
...
begin() and v
...
5):
[1] the compiler first looks for members begin and end and tries to use those
...
g
...

[2] Otherwise, the compiler looks for a begin/end member pair in the enclosing scope
...
g
...

The compiler uses v and v+N as begin(v) and end(v) for a built-in array T v[N]
...
For
sequences of our own design, we can define begin() and end() in the same way as it is done for standard-library containers (§4
...
5)
...

For example, we can increment each element of a vector like this:
void incr(vector& v)
{
for (int& x : v)
++x;
}

References are also appropriate for elements that might be large, so that copying them to the element value could be costly
...
For example, using it you can’t touch
two elements at the same time and can’t effectively traverse two ranges simultaneously
...


Section 9
...
2

for

Statements

235

9
...
2 for Statements
There is also a more general for-statement allowing greater control of the iteration
...
For example:
void f(int v[], int max)
{
for (int i = 0; i!=max; ++i)
v[i] = i∗i;
}

This is equivalent to
void f(int v[], int max)
{
int i = 0;
// introduce loop variable
while (i!=max) {
// test termination condition
v[i] = i∗i; // execute the loop body
++i;
// increment loop variable
}
}

A variable can be declared in the initializer part of a for-statement
...

It is not always obvious what is the right type to use for a controlled variable in a for loop, so
auto often comes in handy:
for (auto p = begin(c); c!=end(c); ++p) {
//
...

}

If the final value of an index needs to be known after exit from a for-loop, the index variable must
be declared outside the for-loop (e
...
, see §9
...

If no initialization is needed, the initializing statement can be empty
...
If the loop isn’t of the simple ‘‘introduce a loop variable, test the condition, update the loop variable’’ variety, it is often better
expressed as a while-statement
...
push_back(s);

Here, the reading and testing for termination and combined in cin>>s, so we don’t need an explicit
loop variable
...

A for-statement is also useful for expressing a loop without an explicit termination condition:
for (;;) { // ‘‘forever’’
//
...

}

// ‘‘forever’’

9
...
3 while Statements
A while-statement executes its controlled statement until its condition becomes false
...

A for-statement (§9
...
2) is easily rewritten into an equivalent while-statement and vice versa
...
5
...
For

// i must be positive

This might be called like this: print_backwards(s,strlen(s)); but it is all too easy to make a horrible
mistake
...
The reason is that its
body is always executed once before the condition is evaluated
...
More often
than I would have guessed, I have found that condition not to hold as expected either when the program was first written and tested or later after the code preceding it has been modified
...
’’ Consequently, I recommend avoiding do-statements
...
5
...
1
...
6), throw
(§13
...
4
...
A break ‘‘breaks out of’’ the

Section 9
...
5

Loop Exit

237

nearest enclosing switch-statement (§9
...
2) or iteration-statement
...

if (c == '\n') break;
//
...
’’ Unless it warps the logic of
a loop (e
...
, requires the introduction of an extra varible), it is usually better to have the complete
exit condition as the condition of a while-statement or a for-statement
...
A continue skips the rest of the body of an iteration-statement
...
size(); ++i) {
if (!prime(v[i]) continue;
return v[i];
}
}

After a continue, the increment part of the loop (if any) is executed, followed by the loop condition
(if any)
...
size(); ++i) {
if (!prime(v[i]) {
return v[i];
}
}
}

9
...


238

Statements

Chapter 9

The scope of a label is the function it is in (§6
...
4)
...
The only restriction is that you cannot jump past an initializer or into
an exception handler (§13
...

One of the few sensible uses of goto in ordinary code is to break out from a nested loop or
switch-statement (a break breaks out of only the innermost enclosing loop or switch-statement)
...

found:
// nm[i][j] == a
}

Note that this goto just jumps forward to exit its loop
...
That makes it the least troublesome and least confusing use of a goto
...
7 Comments and Indentation
Judicious use of comments and consistent use of indentation can make the task of reading and
understanding a program much more pleasant
...
I see no fundamental reason to prefer one over another (although, like most programmers, I
have my preferences, and this book reflects them)
...

Comments can be misused in ways that seriously affect the readability of a program
...

Most programs contain comments that are incomprehensible, ambiguous, and just plain wrong
...

If something can be stated in the language itself, it should be, and not just mentioned in a comment
...
7

Comments and Indentation

239

// don’t use function "weird()"
// function "f(int
...

Once something has been stated clearly in the language, it should not be mentioned a second
time in a comment
...
They increase the amount of text the reader has
to look at, they often obscure the structure of the program, and they may be wrong
...
This is one of the many ways a program in a textbook differs from a real program
...
Preferably, a comment is expressed
at a suitably high level of abstraction so that it is easy for a human to understand without delving
into minute details
...

• A comment for each class, template, and namespace
• A comment for each nontrivial function stating its purpose, the algorithm used (unless it is
obvious), and maybe something about the assumptions it makes about its environment
• A comment for each global and namespace variable and constant
• A few comments where the code is nonobvious and/or nonportable
• Very little else
For example:
//

tbl
...


/*

Gaussian elimination with partial pivoting
...
" pg 411
...

// Revised to handle invalid dates
...
Writing
good comments can be as difficult as writing the program itself
...


240

Statements

Chapter 9

Note that /∗ ∗/ style comments do not nest
...


9
...
3, §9
...
3, §9
...
2
...
4
...

Prefer a range-for-statement to a for-statement when there is a choice; §9
...
1
...
5
...

Prefer a while-statement to a for-statement when there is no obvious loop variable; §9
...
3
...
5
...
6
...
7
...
7
...
7
...
7
...

– apologies to Richard Feynman










Introduction
A Desk Calculator
The Parser; Input; Low-Level Input; Error Handling; The Driver; Headers; Command-Line
Arguments; A Note on Style
Operator Summary
Results; Order of Evaluation; Operator Precedence; Temporary Objects
Constant Expressions
Symbolic Constants; consts in Constant Expressions; Literal Types; Reference Arguments;
Address Constant Expressions
Implicit Type Conversion
Promotions; Conversions; Usual Arithmetic Conversions
Advice

10
...
In C++, an assignment is an expression, a function call is an expression, the construction of an object is an expression, and so are many other
operations that go beyond conventional arithmetic expression evaluation
...
’’ Next, the complete set of operators is listed and their meaning for builtin types is briefly outlined
...


242

Expressions

Chapter 10

10
...
The user can also define variables
...
5
area = pi ∗ r ∗ r

(pi is predefined) the calculator program will write
2
...
635

where 2
...
635 is the result of the second
...
Actually, it is a miniature compiler in which the parser does the syntactic analysis, the input
function handles input and lexical analysis, the symbol table holds permanent information, and the
driver handles initialization, output, and errors
...


10
...
1 The Parser
Here is a grammar for the language accepted by the calculator:
program:
end
expr_list end

// end is end-of-input

expr_list:
expression print
expression print expr_list

// print is newline or semicolon

expression:
expression + term
expression − term
term
term:
term / primary
term ∗ primary
primary
primary:
number
name
name = expression
− primary
( expression )

// number is a floating-point literal
// name is an identifier

Section 10
...
1

The Parser

243

In other words, a program is a sequence of expressions separated by semicolons
...
Names need not be declared before use
...
In a language such as C++, in which function calls are relatively cheap, it is also
efficient
...
Terminal symbols (for example, end, number, +, and −) are recognized by a lexical analyzer and nonterminal symbols are recognized by the syntax analyzer functions, expr(), term(), and prim()
...

For input, the parser uses a Token_stream that encapsulates the reading of characters and their
composition into Tokens
...
45, into Tokens
...
45}, where the
123
...
The main parts of the parser need only to know
the name of the Token_stream, ts, and how to get Tokens from it
...
get()
...
current()
...
We’ll see that
they can come directly from a user typing to cin, from a program command line, or from any other
input stream (§10
...
7)
...
This works as long as no character used as input has a value used
as an enumerator – and no current character set I know of has a printing character with a singledigit integer value
...

};

The implementation is presented in §10
...
2
...
2
...
Each parser function evaluates ‘‘its’’

244

Expressions

Chapter 10

expression and returns the value
...
It consists
of a single loop that looks for terms to add or subtract:
double expr(bool get)
{
double left = term(get);

// add and subtract

for (;;) {
// ‘‘forever’’
switch (ts
...
kind) {
case Kind::plus:
left += term(true);
break;
case Kind::minus:
left −= term(true);
break;
default:
return left;
}
}
}

This function really does not do much itself
...

The switch-statement (§2
...
4, §9
...
2) tests the value of its condition, which is supplied in parentheses after the switch keyword, against a set of constants
...
If the value tested does not match any case label, the default is chosen
...

Note that an expression such as 2−3+4 is evaluated as (2−3)+4, as specified in the grammar
...
5); while(true) is an alternative
...

The operators += and −= are used to handle the addition and subtraction; left=left+term(true) and
left=left−term(true) could have been used without changing the meaning of the program
...
Each assignment operator is a separate lexical token, so a + = 1; is a syntax error because
of the space between the + and the =
...
3 summarizes the operators
and their meanings
...


Section 10
...
1

The Parser

245

The function term() handles multiplication and division in the same way expr() handles addition
and subtraction:
double term(bool get)
{
double left = prim(get);

// multiply and divide

for (;;) {
switch (ts
...
kind) {
case Kind::mul:
left ∗= prim(true);
break;
case Kind::div:
if (auto d = prim(true)) {
left /= d;
break;
}
return error("divide by 0");
default:
return left;
}
}
}

The result of dividing by zero is undefined and usually disastrous
...
The function error() is described in §10
...
4
...
The scope of a name introduced in a condition is the statement controlled by that condition,
and the resulting value is the value of the condition (§9
...
3)
...

The function prim() handling a primary is much like expr() and term(), except that because we are
getting lower in the call hierarchy a bit of real work is being done and no loop is necessary:
double prim(bool get)
// handle primaries
{
if (get) ts
...
current()
...
current()
...
get();
return v;
}
case Kind::name:
{
double& v = table[ts
...
string_value];
if (ts
...
kind == Kind::assign) v = expr(true);
return v;
}

// find the corresponding
// ’=’ seen: assignment

246

Expressions

Chapter 10

case Kind::minus:
// unar y minus
return −prim(true);
case Kind::lp:
{
auto e = expr(true);
if (ts
...
kind != Kind::rp) return error("')' expected");
ts
...
Similarly, when a Token that is a name (however defined; see §10
...
2 and
§10
...
3) is seen, its value is placed in its string_value
...

The reason is that it must do that in some cases (e
...
, to see if a name is assigned to), so for consistency it must do it in all cases
...
get()
...
current()
...
get())
...
In both cases, the symbol table is consulted
...
4
...
4
...
For example, if the user enters

double

corresponding to the

radius = 6378
...
expr() calculates the value to be assigned
...
388;

The reference v is used to hold on to the double associated with radius while expr() calculates the
value 6378
...

Chapter 14 and Chapter 15 discuss how to organize a program as a set of modules
...
The exception is expr(), which calls term(), which calls
prim(), which in turn calls expr()
...
A declaration
double expr(bool);

before the definition of prim() will do nicely
...
2
...
2
...
To communicate with a person, the program
must cope with that person’s whims, conventions, and seemingly random errors
...
The task of a low-level input routine is to read characters and compose higher-level tokens
from them
...
Here, low-level input
is done by ts
...
Writing a low-level input routine need not be an everyday task
...

First we need to see the complete definition of Token_stream:
class Token_stream {
public:
Token_stream(istream& s) : ip{&s}, owns{false} { }
Token_stream(istream∗ p) : ip{p}, owns{true} { }
˜Token_stream() { close(); }
Token get();
Token& current();

// read and return next token
// most recently read token

void set_input(istream& s) { close(); ip = &s; owns=false; }
void set_input(istream∗ p) { close(); ip = p; owns = true; }
private:
void close() { if (owns) delete ip; }
istream∗ ip;
bool owns;
Token ct {Kind::end} ;

// pointer to an input stream
// does the Token_stream own the istream?
// current token

};

We initialize a Token_stream with an input stream (§4
...
2, Chapter 38) from which it gets its characters
...
2
...
2,
§11
...
This may be a bit
elaborate for this simple program, but it is a useful and general technique for classes that hold a
pointer to a resource requiring destruction
...

I gave ct a default value because it seemed sloppy not to
...
I chose Kind::end as the initial value for ct so
that a program that misuses current() will not get a value that wasn’t on the input stream
...
First, I provide a deceptively simple version that
imposes a burden on the user
...
The idea for get() is to read a character, use that character to decide what kind of token
needs to be composed, read more characters when needed, and then return a Token representing the
characters read
...
) and leaves the value
of ch unchanged if the input operation failed
...

Assignment is an operator, and the result of the assignment is the value of the variable assigned
to
...

Having a single statement rather than two is useful in maintenance
...

Note also how the {}-list notation (§3
...
1
...
3) is used on the right-hand side of an assignment
...
I could have written that return-statement as:
ct
...
The {Kind::end} is equivalent to {Kind::end,0,0}
...
Neither is the
case here, but in general dealing with complete objects is clearer and less error-prone than manipulating data members individually
...

Consider some of the cases separately before considering the complete function
...
5
...
4
...

Numbers are handled like this:
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
case '
...
2
...
) back into the input stream
∗ip >> ct
...
kind=Kind::number;
return ct;

Stacking case labels horizontally rather than vertically is generally not a good idea because this
arrangement is harder to read
...
Because operator >> is already defined for reading floating-point values into a double, the code is trivial
...
Then, the floating-point value can be read
into ct
...

If the token is not the end of input, an operator, a punctuation character, or a number, it must be
a name
...
string_value;
// read the string into ct
ct
...
The simple-minded, but reasonably effective way to deal
with an error is the write call an error() function and then return a print token if error() returns:
error("bad token");
return ct={Kind::print};

The standard-library function isalpha() (§36
...
1) is used to avoid listing every character as a separate case label
...
Consequently, a user must terminate a name by a space before an operator using the name
as an operand
...
2
...

Here, finally, is the complete input function:
Token Token_stream::get()
{
char ch = 0;
∗ip>>ch;
switch (ch) {
case 0:
return ct={Kind::end};
// assign and return
case ';': // end of expression; print
case '∗':
case '/':
case '+':
case '−':
case '(':
case ')':
case '=':
return ct=={static_cast(ch)};

250

Expressions

Chapter 10

case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
case '
...
) back into the input stream
∗ip >> ct
...
kind=Kind::number;
return ct;
default:
// name, name =, or error
if (isalpha(ch)) {
ip−>putback(ch);
// put the first character back into the input stream
∗ip>>ct
...
kind=Kind::name;
return ct;
}
error("bad token");
return ct={Kind::print};
}
}

The conversion of an operator to its Token value is trivial because the
defined as the integer value of the operator (§10
...
1)
...
2
...
It is tedious to remember to
add a semicolon after an expression in order to get its value printed, and having a name terminated
by whitespace only is a real nuisance
...
To get what we (usually) want, we would have to add
whitespace after x: x =7
...

First, we’ll make a newline equivalent to the semicolon used to mark the end-of-expression:
Token Token_stream::get()
{
char ch;
do { // skip whitespace except ’\n’
if (!ip−>get(ch)) return ct={Kind::end};
} while (ch!='\n' && isspace(ch));
switch (ch) {
case ';':
case '\n':
return ct={Kind::print};

Here, I use a do-statement; it is equivalent to a while-statement except that the controlled statement
is always executed at least once
...
By default, get() does not skip whitespace the way >> does
...
The operator ! (not) is used because get() returns true in case of success
...
2
...
2
...
The test is
implemented as a table lookup, so using isspace() is much faster than testing for the individual
whitespace characters
...

After whitespace has been skipped, the next character is used to determine what kind of lexical
token is coming
...
Constructing programs so that improvements can be implemented through local modifications only is an important design aim
...
It
would be for very long strings, but all modern string implementations provide the ‘‘small string
optimization’’ (§19
...
3)
...
In particular,
using a short string doesn’t require any use of free store
...


10
...
4 Error Handling
It is always important to detect and report errors
...
The error() function simply counts the errors, writes out an error message,
and returns:
int no_of_errors;
double error(const string& s)
{
no_of_errors++;
cerr << "error: " << s << '\n';
return 1;
}

The stream cerr is an unbuffered output stream usually used to report errors (§38
...

The reason for returning a value is that errors typically occur in the middle of the evaluation of
an expression, so we should either abort that evaluation entirely or return a value that is unlikely to
cause subsequent errors
...
Had Token_stream::get()

252

Expressions

Chapter 10

kept track of the line numbers, error() could have informed the user approximately where the error
occurred
...

A more stylized and general error-handling strategy would separate error detection from error
recovery
...
4
...
1, Chapter 13), but what we have
here is quite suitable for a 180-line calculator
...
2
...
I decided on two
functions: main() to do setup and error reporting and calculate() to handle the actual calculation:
Token_stream ts {cin};

// use input from cin

void calculate()
{
for (;;) {
ts
...
current()
...
current()
...
1415926535897932385;
table["e"] = 2
...
2
...
Returning the number of errors accomplishes this nicely
...

The primary task of the main loop (in calculate()) is to read expressions and write out the
answer
...
get() to read a token on which to work
...
get() encounters an input
error or an end-of-file
...
5)
...
A continue-statement is equivalent to going to the very end of a loop
...
2
...
2
...
Therefore, appropriate headers must be #included to
complete the program:
#include // I/O
#include
// strings
#include
// map
#include // isalpha(), etc
...
Chapter
14 and Chapter 15 discuss ways of organizing this calculator into modules using namespaces and
how to organize it into source files
...
2
...
My most common use was to evaluate a single expression
...

A program starts by calling main() (§2
...
1, §15
...
When this is done, main() is given two arguments specifying the number of arguments, conventionally called argc, and an array of arguments,
conventionally called argv
...
2
...
3), so the type
of argv is char∗[argc+1]
...
The list of arguments is zero-terminated; that is, argv[argc]==0
...
1934

the arguments have these values:
argc:

2

argv:

0

"dc"
"150/1
...

The idea is to read from the command string in the same way that we read from the input
stream
...
2
...
So to
calculate expressions presented on the command line, we simply have to get our Token_stream to
read from an appropriate istringstream:

254

Expressions

Chapter 10

Token_stream ts {cin};
int main(int argc, char∗ argv[])
{
switch (argc) {
case 1:
// read from standard input
break;
case 2:
// read from argument string
ts
...
1415926535897932385;
table["e"] = 2
...

It would be easy to modify main() to accept several command-line arguments, but this does not
appear to be necessary, especially as several expressions can be passed as a single argument:
dc "rate=1
...
75/rate;217/rate"

I use quotes because ; is the command separator on my UNIX systems
...

Simple as they are, argc and argv are still a source of minor, yet annoying, bugs
...
push_back(argv[i]);
return res;
}

More elaborate argument parsing functions are not uncommon
...
2
...
It is not
...
Often, a library has received more care in its design and implementation than a

Section 10
...
8

A Note on Style

255

programmer could afford for a handcrafted piece of code to be used in just one program
...
Many of the traditional tricky details have been
replaced by uses of standard-library classes such as ostream, string, and map (§4
...
1, §4
...
4
...
4, Chapter 36, Chapter 38)
...
This is the way things ought to
be in code that doesn’t manipulate hardware directly or implement low-level abstractions
...
3 Operator Summary
This section presents a summary of expressions and some examples
...
In these tables:
• A name is an identifier (e
...
, sum and map), an operator name (e
...
, operator int, operator+,
and operator"" km), or the name of a template specialization (e
...
, sort and
array), possibly qualified using :: (e
...
, std::vector and vector::operator[])
...

• A member is a member name (including the name of a destructor or a member template)
...

• A pointer is an expression yielding a pointer (including this and an object of that type that
supports the pointer operation)
...
g
...

• An lvalue is an expression denoting a modifiable object (§6
...
1)
...
) only when it appears in parentheses; elsewhere, there are restrictions (§iso
...

• A lambda-declarator is a (possibly empty, comma-separated) list of parameters optionally
followed by the mutable specifier, optionally followed by a noexcept specifier, optionally followed by a return type (§11
...

• A capture-list is a (possibly empty) list specifying context dependencies (§11
...

• A stmt-list is a (possibly empty) list of statements (§2
...
4, Chapter 9)
...
The meanings presented here apply
when the operands are of built-in types (§6
...
1)
...
3, Chapter 18)
...
For details, see §iso
...
A
...
5
...
4
§16
...
3
§14
...
1
§14
...
1

Each box holds operators with the same precedence
...
For example, N::x
...
m rather than the illegal N::(x
...


256

Expressions

Chapter 10

Operator Summary (continued, continues)
Member selection
Member selection
Subscripting
Function call
Value construction
Function-style type conversion
Post increment
Post decrement
Type identification
Run-time type identification
Run-time checked conversion
Compile-time checked conversion
Unchecked conversion
const conversion
Size of object
Size of type
Size of parameter pack
Alignment of type
Pre increment
Pre decrement
Complement
Not
Unary minus
Unary plus
Address of
Dereference
Create (allocate)
Create (allocate and initialize)
Create (allocate and initialize)
Create (place)
Create (place and initialize)
Create (place and initialize)
Destroy (deallocate)
Destroy array
Can expression throw?
Cast (type conversion)
Member selection
Member selection

object
...
name
alignof ( type )
++ lvalue
−− lvalue
˜ expr
! expr
− expr
+ expr
& lvalue
∗ expr
new type
new type ( expr-list )
new type { expr-list }
new ( expr-list ) type
new ( expr-list ) type ( expr-list )
new ( expr-list ) type { expr-list }
delete pointer
delete [] pointer
noexcept ( expr )
( type ) expr
object
...
2
...
2
...
3
§12
...
3
...
5
...
1
...
1
...
5
§22
...
2
...
5
...
5
...
5
...
2
...
2
...
6
...
2
...
1
...
1
...
1
...
1
...
2
...
2
...
2
§7
...
2
§11
...
2
§11
...
4
§11
...
4
§11
...
4
§11
...
2
...
5
...
2
§11
...
3
§20
...
6

For example, postfix ++ has higher precedence than unary ∗, so ∗p++ means ∗(p++), not (∗p)++
...
3

Operator Summary

257

Operator Summary (continued)
Multiply
Divide
Modulo (remainder)
Add (plus)
Subtract (minus)
Shift left
Shift right
Less than
Less than or equal
Greater than
Greater than or equal
Equal
Not equal
Bitwise and
Bitwise exclusive-or
Bitwise inclusive-or
Logical and
Logical inclusive or
Conditional expression
List
Throw exception
Simple assignment
Multiply and assign
Divide and assign
Modulo and assign
Add and assign
Subtract and assign
Shift left and assign
Shift right and assign
Bitwise and and assign
Bitwise inclusive-or and assign
Bitwise exclusive-or and assign
comma (sequencing)

expr ∗ expr
expr / expr
expr % expr
expr + expr
expr − expr
expr << expr
expr >> expr
expr < expr
expr <= expr
expr > expr
expr >= expr
expr == expr
expr != expr
expr & expr
expr ˆ expr
expr | expr
expr && expr
expr || expr
expr ? expr : expr
{ expr-list }
throw expr
lvalue = expr
lvalue ∗= expr
lvalue /= expr
lvalue %= expr
lvalue += expr
lvalue −= expr
lvalue <<= expr
lvalue >>= expr
lvalue &= expr
lvalue |= expr
lvalue ˆ= expr
expr , expr

§10
...
1
§10
...
1
§10
...
1
§10
...
1
§10
...
1
§11
...
2
§11
...
2
§2
...
2
§2
...
2
§2
...
2
§2
...
2
§2
...
2
§2
...
2
§11
...
2
§11
...
2
§11
...
2
§11
...
1
§11
...
1
§11
...
3
§11
...
5
§10
...
1
§10
...
1
§10
...
1
§10
...
1
§10
...
1
§10
...
1
§10
...
1
§10
...
1
§10
...
1
§10
...
1
§10
...
1
§10
...
2

For example: a+b∗c means a+(b∗c) rather than (a+b)∗c because ∗ has higher precedence than +
...

For example, a=b=c means a=(b=c) whereas a+b+c means (a+b)+c
...
For example, a=blook at the grammar (§iso
...


258

Expressions

Chapter 10

Before applying the grammar rules, lexical tokens are composed from characters
...
For example, && is a single operator,
rather than two & operators, and a+++1 means (a ++) + 1
...

Token Summary (§iso
...
7)
Token Class
Identifier
Keyword
Character literal
Integer literal
Floating-point literal
String literal
Operator
Punctuation
Preprocessor notation

Examples
vector, foo_bar, x3
int, for, virtual
’x’, \n’, ’U’\UFADEFADE’
12, 012, 0x12
1
...
2e−3, 1
...
3
...
3
...
1
§6
...
3
...
2
...
1
§6
...
5
...
3
...
3
§12
...
g
...
g
...

Some characters from the basic source character set (§6
...
2), such as |, are not convenient to
type on some keywords
...
Consequently, a set of alternative representation are provided as
keywords:
Alternative Representation (§iso
...
12)
and
&

and_eq
&=

bitand
&

bitor
|

compl
˜

not
!

not_eq
!=

or
|

or_eq
|=

xor
ˆ

xor_eq
ˆ=

For example
bool b = not (x or y) and z;
int x4 = ˜ (x1 bitor x2) bitand x3;

is equivalent to
bool b = !(x || y) && z;
int x4 = ˜(x1 | x2) & x3;

Note that and= is not equivalent to &=; if you prefer keywords, you must write and_eq
...
3
...
5
...
The overall aim is to produce a result of the ‘‘largest’’ operand type
...
Similarly, if it has a long operand, the
computation is done using long integer arithmetic, and the result is a long
...


Section 10
...
1

Results

259

The relational operators, ==, <=, etc
...
The meaning and result type of
user-defined operators are determined by their declarations (§18
...

Where logically feasible, the result of an operator that takes an lvalue operand is an lvalue
denoting that lvalue operand
...
Preserving lvalues in this way allows greater flexibility in using operators
...
g
...

The result of sizeof is of an unsigned integral type called size_t defined in
...

Implementations do not have to check for arithmetic overflow and hardly any do
...
What happens then is undefined, but
typically the value ‘‘wraps around’’ to a negative number (on my machine −2147483648)
...
In particular, underflow, overflow, and division by zero do not throw standard exceptions
(§30
...
1
...


10
...
2 Order of Evaluation
The order of evaluation of subexpressions within an expression is undefined
...
For example:
int x = f(2)+g(3);

// undefined whether f() or g() is called first

Better code can be generated in the absence of restrictions on expression evaluation order
...
For example:
int i = 1;
v[i] = i++; // undefined result

The assignment may be evaluated as either v[1]=1 or v[2]=1 or may cause some even stranger behavior
...
Unfortunately, most do not, so be careful not to
write an expression that reads or writes an object more than once, unless it does so using a single

260

Expressions

Chapter 10

operator that makes it well defined, such as ++ and +=, or explicitly express sequencing using ,
(comma), &&, or ||
...
For example, b=(a=2,a+1) assigns 3 to b
...
3
...
For built-in types, the second operand of && is
evaluated only if its first operand is true, and the second operand of || is evaluated only if its first operand is false; this is sometimes called short-circuit evaluation
...
For
example:
f1(v[i],i++);
f2( (v[i],i++) );

// two arguments
// one argument

The call of f1 has two arguments, v[i] and i++, and the order of evaluation of the argument expressions is undefined
...
Order dependence of argument expressions is very
poor style and has undefined behavior
...
That is confusing, so that too should be avoided
...
For example, a∗b/c means (a∗b)/c, so parentheses
must be used to get a∗(b/c); a∗(b/c) may be evaluated as (a∗b)/c only if the user cannot tell the difference
...


10
...
3 Operator Precedence
Precedence levels and associativity rules reflect the most common usage
...


means ‘‘if i is less than or equal to 0 or if max is less than i
...


and not the legal but nonsensical
if (i <= (0||max) < i) //
...
Use of
parentheses becomes more common as the subexpressions become more complicated, but complicated subexpressions are a source of errors
...

There are cases when the operator precedence does not result in the ‘‘obvious’’ interpretation
...
Because == has higher precedence
than &, the expression is interpreted as i&(mask==0)
...
In this case, parentheses are important:
if ((i&mask) == 0) //
...
3
...


This is legal, but it is interpreted as (0<=x)<=99, where the result of the first comparison is either true
or false
...
To test whether x is in the range 0
...


A common mistake for novices is to use = (assignment) instead of == (equals) in a condition:
if (a = 7) // oops! constant assignment in condition

This is natural because = means ‘‘equals’’ in many languages
...
I do not recommend warping your style to compensate for compilers with weak warnings
...
3
...
For
example, for v=x+y∗z the result of y∗z has to be put somewhere before it is added to x
...
However, for a user-defined type that holds a resource knowing the lifetime of a
temporary can be important
...
A full
expression is an expression that is not a subexpression of some other expression
...
3) that returns a C-style pointer to a zeroterminated array of characters (§2
...
5, §43
...
Also, the operator + is defined to mean string concatenation
...
However, in combination they can cause obscure
problems
...
c_str();
cout << cs;
if (strlen(cs=(s2+s3)
...
However, such code does get written, so it is worth knowing how it is interpreted
...
Next, a pointer to a C-style string is
extracted from that object
...

However, the C-style string returned by c_str() was allocated as part of the temporary object holding
s1+s2, and that storage is not guaranteed to exist after that temporary is destroyed
...
The output operation cout<would be sheer luck
...


262

Expressions

Chapter 10

The problem with the if-statement is a bit more subtle
...

However, that temporary is destroyed before the controlled statement is entered, so any use of cs
there is not guaranteed to work
...
A cleaner programming style yields a more understandable program fragment and avoids the problems with temporaries completely
...
length()<8 && s[0]=='a') {
// use s here
}
}

A temporary can be used as an initializer for a const reference or a named object
...
The temporary is destroyed when ‘‘its’’ reference or named object goes out of scope
...
1
...
7)
...
5
...
For example:
void f(Shape& s, int n, char ch)
{
s
...

}

Such temporaries are destroyed in exactly the same way as the implicitly generated temporaries
...
4 Constant Expressions
C++ offers two related meanings of ‘‘constant’’:
• constexpr: Evaluate at compile time (§2
...
3)
...
2
...
5)
...
4

Constant Expressions

263

primary role is to specify immutability in interfaces
...

A constant expression is an expression that a compiler can evaluate
...
Ultimately, a constant expression
must start out with an integral value (§6
...
1), a floating-point value (§6
...
5), or an enumerator
(§8
...
In addition, some addresses can be used in some forms of constant expressions
...
4
...

There are a variety of reasons why someone might want a named constant rather than a literal or
a value stored in a variable:
[1] Named constants make the code easier to understand and maintain
...

[3] The language requires constant expressions for array sizes, case labels, and template
value arguments
...
Also, data in read-only memory is immune to
most system crashes
...

[6] Sometimes, evaluating something once (at compile time) gives significantly better performance than doing so a million times at run time
...
We don’t just use constant expressions
because of an obsession with performance
...

As part of the definition of a data item (here, I deliberately avoid the word ‘‘variable’’),
constexpr expresses the need for compile-time evaluation
...
For example:
int x1 = 7;
constexpr int x2 = 7;
constexpr int x3 = x1;
constexpr int x4 = x2;

// error : initializer is not a constant expression
// OK

void f()
{
constexpr int y3 = x1;
constexpr int y4 = x2;
//
...
However, we
prefer not to rely on degrees of cleverness in compilers
...


264

Expressions

Chapter 10

The expressive power of constant expressions is great
...
We can use any operator that doesn’t modify state (e
...
, +, ?:, and [], but not =
or ++)
...
1
...
4
...
It is almost unfair to compare this to what is commonly
done with macros (§12
...

The conditional-expression operator ?: is the means of selection in a constant expression
...
The alternative not
selected is not evaluated and might even not be a constant expression
...
This feature is primarily useful in
constexpr functions that are sometimes used as constant expressions and sometimes not
...
4
...
Symbolic names should be used systematically to avoid ‘‘magic numbers’’
in code
...

If a numeric constant, such as an array bound, is repeated in code, it becomes hard to revise that
code because every occurrence of that constant must be changed to update the code correctly
...
Usually, a numeric constant represents an
assumption about the program
...
24 the exchange factor between Danish
kroner and U
...
dollars
...
Also, many such values need to change over time
...
Representing assumptions as well-commented
named (symbolic) constants minimizes such maintenance problems
...
4
...
5)
...
For example:

const

can also be used to express

Section 10
...
2

consts

in Constant Expressions

265

const int x = 7;
const string s = "asdf";
const int y = sqrt(x);

A const initialized with a constant expression can be used in a constant expression
...
For example:
constexpr int xx = x;
constexpr string ss = s;
constexpr int yy = y;

// OK
// error : s is not a constant expression
// error : sqr t(x) is not a constant expression

The reasons for the errors are that string is not a literal type (§10
...
3) and sqrt() is not a constexpr
function (§12
...
6)
...
In many cases, enumerators (§8
...


10
...
3 Literal Types
A sufficiently simple user-defined type can be used in a constant expression
...

};

A class with a constexpr constructor is called a literal type
...
For example:
constexpr Point origo {0,0};
constexpr int z = origo
...
move(3,3)
};
constexpr int x = a[1]
...

Naturally, we can define constexpr functions to take arguments of literal types
...
x)+square(p
...
z));
}
constexpr Point p1 {10,20,30};
// the default constructor is constexpr
constexpr p2 {p1
...

For a member function constexpr implies const, so I did not have to write:
constexpr Point move(int dx, int dy) const { return {x+dx,y+dy}; }

10
...
4 Reference Arguments
When working with constexpr, the key thing to remember is that constexpr is all about values
...
That said, you might guess that constexpr cannot
deal with references, but that’s only partially true because const references refer to values and can
therefore be used
...
0, double im = 0
...

};

Obviously, operations, such as = and +=, that modify an object cannot be constexpr
...
The interesting member is the template constructor from
another complex type
...
real();
constexpr double im = z1
...
4
...

Literal types allow for type-rich compile-time programming
...
This has resulted in
code that was unnecessarily complicated and error-prone, as people encoded every kind of information as integers
...

Other programmers have simply preferred run-time evaluation to avoid the difficulties of writing in
an impoverished language
...
4
...
4
...
However, its value is assigned by the linker, rather than the compiler, so the compiler cannot know the
value of such an address constant
...
For example:
constexpr const char∗ p1 = "asdf";
constexpr const char∗ p2 = p1;
constexpr const char∗ p2 = p1+2;
constexpr char c = p1[2];

// OK
// error : the compiler does not know the value of p1
// OK, c==’d’; the compiler knows the value pointed to by p1

10
...
2
...

Wherever possible, values are converted so as not to lose information
...
A conversion is value-preserving if you can convert a value and then convert the result back to its original type and get the
original value
...
5
...
6)
...


10
...
1 Promotions
The implicit conversions that preserve values are commonly referred to as promotions
...
Similarly, floating-point promotion is used to create doubles out of floats
...
This reflects the original purpose of
these promotions in C: to bring operands to the ‘‘natural’’ size for arithmetic operations
...

• A char16_t, char32_t, wchar_t (§6
...
3), or a plain enumeration type (§8
...
2) is converted to
the first of the following types that can represent all the values of its underlying type: int,
unsigned int, long, unsigned long, or unsigned long long
...
2
...
Otherwise, no integral promotion applies to it
...

Promotions are used as part of the usual arithmetic conversions (§10
...
3)
...
5
...
4)
...
For example:
void f(double d)
{
char c = d;
}

// beware: double-precision floating-point to char conversion

When writing code, you should always aim to avoid undefined behavior and conversions that quietly throw away information (‘‘narrowing conversions’’)
...
Fortunately, many compilers do
...
3
...
For example:
void f(double d)
{
char c {d};
}

// error: double-precision floating-point to char conversion

If potentially narrowing conversions are unavoidable, consider using some form of run-time
checked conversion function, such as narrow_cast<>() (§11
...


10
...
2
...
A plain enumeration value can be converted to
an integer type (§8
...
2)
...
More precisely, the result
is the least unsigned integer congruent to the source integer modulo 2 to the nth, where n is the
number of bits used to represent the unsigned type
...
2
...

A Boolean or plain enumeration value can be implicitly converted to its integer equivalent
(§6
...
2, §8
...


Section 10
...
2
...
5
...
2 Floating-Point Conversions
A floating-point value can be converted to another floating-point type
...
If the source
value is between two adjacent destination values, the result is one of those values
...
For example:
float f = FLT_MAX;
double d = f;

// largest float value
// OK: d == f

double d2 = DBL_MAX; // largest double value
float f2 = d2;
// undefined if FLT_MAXlong double ld = d2;
// OK: ld = d3
long double ld2 = numeric_limits::max();
double d3 = ld2;
// undefined if sizeof(long double)>sizeof(double)
DBL_MAX

and FLT_MAX are defined in ; numeric_limits is defined in (§40
...


10
...
2
...
2
...
A pointer (reference)
to a derived class can be implicitly converted to a pointer (reference) to an accessible and unambiguous base (§20
...
Note that a pointer to function or a pointer to member cannot be implicitly
converted to a void∗
...
4) that evaluates to 0 can be implicitly converted to a null pointer of
any pointer type
...
6)
...
2
...

A T∗ can be implicitly converted to a
verted to a const T&
...
5)
...
5
...
4 Pointer-to-Member Conversions
Pointers and references to members can be implicitly converted as described in §20
...
3
...
5
...
5 Boolean Conversions
Pointer, integral, and floating-point values can be implicitly converted to
value converts to true; a zero value converts to false
...

}

// true if p!=0
// true if i!=0

bool

(§6
...
2)
...

fi(p);
// error : no pointer to int conversion
fb(p);
// OK: pointer to bool conversion (surprise!?)
}

Hope for a compiler warning for fb(p)
...
5
...
6 Floating-Integral Conversions
When a floating-point value is converted to an integer value, the fractional part is discarded
...
For example, the
value of int(1
...
The behavior is undefined if the truncated value cannot be represented in the
destination type
...
7;
char b = 2000
...

Loss of precision occurs if an integral value cannot be represented exactly as a value of the floating
type
...

Clearly, it is best to avoid potentially value-destroying implicit conversions
...
However, general compile-time detection is impractical, so the programmer must
be careful
...
For
example:
char checked_cast(int i)
{
char c = i;
// warning: not portable (§10
...
2
...

}

Section 10
...
2
...
2
...
1
...
2)
...
3
...


10
...
3 Usual Arithmetic Conversions
These conversions are performed on the operands of a binary operator to bring them to a common
type, which is then used as the type of the result:
[1] If either operand is of type long double, the other is converted to long double
...

• Otherwise, if either operand is float, the other is converted to float
...
5
...

[2] Otherwise, if either operand is unsigned long long, the other is converted to unsigned long
long
...
Otherwise, if either operand is unsigned long long, the other is converted
to unsigned long long
...

• Otherwise, if either operand is long, the other is converted to long
...

• Otherwise, both operands are int
...
That is yet another reason to avoid mixing unsigned and signed integers
...
6 Advice
[1]
[2]
[3]
[4]

Prefer the standard library to other libraries and to ‘‘handcrafted code’’; §10
...
8
...
2
...

When reading, always consider ill-formed input; §10
...
3
...
) to direct use of language features (e
...
,
ints, statements); §10
...
8
...
3
...

[6] If in doubt about operator precedence, parenthesize; §10
...
3
...
3
...

[8] Avoid narrowing conversions; §10
...
2
...
4
...

[10] Avoid narrowing conversions; §10
...
2
...

– Alan Perlis










Etc
...
1 Etc
...
They have little in common beyond their details not fitting elsewhere in the discussions of operators
...
1
...
The && and || operators evaluate their second argument only if necessary, so they can be used to control evaluation order (§10
...
2)
...


11
...
2 Bitwise Logical Operators
The bitwise logical operators & (and), | (or), ˆ (exclusive or, xor), ˜ (complement), >> (right shift),
and << (left shift) are applied to objects of integral types – that is, char, short, int, long, long long
and their unsigned counterparts, and bool, wchar_t, char16_t, and char32_t
...
The usual arithmetic conversions (§10
...
3) determine the type of the result
...

In this case, each bit of an unsigned integer represents one member of the set, and the number of
bits limits the number of members
...
An enumeration can be used to name the members
of such a set
...

if (state&(badbit|failbit)) // stream not good

The extra parentheses are necessary because & has higher precedence than | (§10
...

A function that reaches the end-of-input might report it like this:
state |= eofbit;

The |= operator is used to add to the state
...

These stream state flags are observable from outside the stream implementation
...
rdstate();
//
...

if (cin
...

}

// rdstate() returns the state
// has anything changed?

Computing differences of stream states is not common
...
For example, consider comparing a bit vector that represents the set of interrupts
being handled with another that represents the set of interrupts waiting to be handled
...
1
...
Convenient bit manipulation can be very important, but for reliability, maintainability, portability, etc
...
For more general notions of a
set, see the standard-library set (§31
...
3) and bitset (§34
...
2)
...
For example, one could
extract the middle 16 bits of a 32-bit int like this:
constexpr unsigned short middle(int a)
{
static_assert(sizeof(int)==4,"unexpected int size");
static_assert(sizeof(short)==2,"unexpected short size");
return (a>>8)&0xFFFF;
}
int x = 0xFF00FF00; // assume sizeof(int)==4
short y = middle(x); // y = 0x00FF

Using fields (§8
...
7) is a convenient shorthand for such shifting and masking
...
The latter
return true or false, and they are primarily useful for writing the test in an if-, while-, or for-statement
(§9
...
5)
...


11
...
3 Conditional Expressions
Some if-statements can conveniently be replaced by conditional-expressions
...

Conditional expressions are important in that they can be used in constant expressions (§10
...

A pair of expressions e1 and e2 can be used as alternatives in a conditional expression, c?e1:e2,
if they are of the same type or if there is a common type T, to which they can both be implicitly
converted
...
5
...
For other types, either e1 must be implicitly convertible to e2’s type or vice versa
...
5
...
For example:
void fct(int∗ p)
{
int i = (p) ? ∗p : std::runtime_error{"unexpected nullptr};
//
...
1
...
Provided lvalue has no side effects, ++lvalue means
lvalue+=1, which again means lvalue=lvalue+1
...
Decrementing is similarly expressed by the −− operator
...
The value of ++x is
the new (that is, incremented) value of x
...
The value
of x++, however, is the old value of x
...

Like adding an int to a pointer, or subtracting it, ++ and −− on a pointer operate in terms of elements of the array into which the pointer points; p++ makes p point to the next element (§7
...
1)
...
For example, one can copy a zero-terminated C-style string like this:
void cpy(char∗ p, const char∗ q)
{
while (∗p++ = ∗q++) ;
}

Like C, C++ is both loved and hated for enabling such terse, expression-oriented coding
...
Consider first a more traditional way of copying
an array of characters:
int length = strlen(q);
for (int i = 0; i<=length; i++)
p[i] = q[i];

This is wasteful
...
Thus, we read the string twice: once to find its length and once to copy it
...
1
...
We can therefore rewrite the example like this:
while ((∗p++ = ∗q++) != 0) { }

In this case, we don’t notice that ∗q is zero until we already have copied it into ∗p and incremented
p
...
Finally, we can
reduce the example further by observing that we don’t need the empty block and that the !=0 is
redundant because the result of an integral condition is always compared to zero anyway
...
Is this version more efficient in time or space than the previous versions? Except for the first
version that called strlen(), not really; the performance will be equivalent and often identical code
will be generated
...
h>

For more general copying, the standard copy algorithm (§4
...
5) can be used
...
Standardlibrary functions may be inlined (§12
...
3) or even implemented using specialized machine instructions
...
Even if it does, the advantage may not exist on some other
handware+compiler combination, and your alternative may give a maintainer a headache
...
2 Free Store
A named object has its lifetime determined by its scope (§6
...
4)
...
For example, it is common to create objects that can be used after returning from the function in which they were created
...
Objects
allocated by new are said to be ‘‘on the free store’’ (also, ‘‘on the heap’’ or ‘‘in dynamic memory’’)
...
2)
...

};

278

Select Operations

Chapter 11

Enode∗ expr(bool get)
{
Enode∗ left = term(get);
for (;;) {
switch (ts
...
kind) {
case Kind::plus:
case Kind::minus:
left = new Enode {ts
...
kind,left,term(true)};
break;
default:
return left;
// return node
}
}
}

In cases Kind::plus and Kind::minus, a new Enode is created on the free store and initialized by the
value {ts
...
kind,left,term(true)}
...

I used the {}-list notation for specifying arguments
...
However, trying the = notation for initializing an object
created using new results in an error:
int∗ p = new int = 7; // error

If a type has a default constructor, we can leave out the initializer, but built-in types are by default
uninitialized
...
To be sure to get default initialization, use {}
...
Then, the space it occupied can be reused by new
...
Consequently, I will assume that objects created by new are manually freed using delete
...
2

Free Store

279

The delete operator may be applied only to a pointer returned by new or to the nullptr
...

If the deleted object is of a class with a destructor (§3
...
1
...
2), that destructor is called by
delete before the object’s memory is released for reuse
...
2
...

• Premature deletion: People delete an object that they have some other pointer to and later
use that other pointer
...

Leaked objects are potentially a bad problem because they can cause a program to run out of space
...
Consider
this example of very bad code:
int∗ p1 = new int{99};
int∗ p2 = p1;
delete p1;
p1 = nullptr;
char∗ p3 = new char{'x'};
∗p2 = 999;
cout << ∗p3 << '\n';

// potential trouble
// now p2 doesn’t point to a valid object
// gives a false sense of safety
// p3 may now point to the memory pointed to by p2
// this may cause trouble
// may not print x

Double deletion is a problem because resource managers typically cannot track what code owns a
resource
...
use *p
...
wait a while
...
Replace int with string in that example, and we’ll see string’s
destructor trying to read memory that has been reallocated and maybe overwritten by other code,
and using what it read to try to delete memory
...

The reason people make these mistakes is typically not maliciousness and often not even simple
sloppiness; it is genuinely hard to consistently deallocate every allocated object in a large program
(once and at exactly the right point in a computation)
...


280

Select Operations

Chapter 11

As alternatives to using ‘‘naked’’ news and deletes, I can recommend two general approaches to
resource management that avoid such problems:
[1] Don’t put objects on the free store if you don’t have to; prefer scoped variables
...
Examples are string,
vector and all the other standard-library containers, unique_ptr (§5
...
1, §34
...
1), and
shared_ptr (§5
...
1, §34
...
2)
...
Many classical uses of free store can be eliminated by using move semantics
(§3
...
5
...

This rule [2] is often referred to as RAII (‘‘Resource Acquisition Is Initialization’’; §5
...
3) and
is the basic technique for avoiding resource leaks and making error handling using exceptions simple and safe
...
push_back(c);
//
...

In this example, push_back() does news to acquire space for its elements and deletes to free space
that it no longer needs
...

The Token_stream from the calculator example is an even simpler example (§10
...
2)
...
For example:
string reverse(const string& s)
{
string ss;
for (int i=s
...
push_back(s[i]);
return ss;
}

Like vector, a string is really a handle to its elements
...
3
...

The resource management ‘‘smart pointers’’ (e
...
, unique_ptr and smart_ptr) are a further example of these ideas (§5
...
1, §34
...
1)
...
2
...

if (n%2) throw runtime_error("odd");
delete[] p1;
// we may never get here
}

For f(3) the memory pointed to by p1 is leaked, but the memory pointed to by p2 is correctly and
implicitly deallocated
...
In addition, new is often used in arguments to resource handles
...
g
...
5)
...
2
...
For example:
char∗ save_string(const char∗ p)
{
char∗ s = new char[strlen(p)+1];
strcpy(s,p);
// copy from p to s
return s;
}
int main(int argc, char∗ argv[])
{
if (argc < 2) exit(1);
char∗ p = save_string(argv[1]);
//
...

Unless you really must use a char∗ directly, the standard-library string can be used to simplify
the save_string():
string save_string(const char∗ p)
{
return string{p};
}
int main(int argc, char∗ argv[])
{
if (argc < 2) exit(1);
string s = save_string(argv[1]);
//
...


282

Select Operations

Chapter 11

To deallocate space allocated by new, delete and delete[] must be able to determine the size of
the object allocated
...
At a minimum, space is needed to hold the
object’s size
...
Most
modern machines use 8-byte words
...
g
...

Note that a vector (§4
...
1, §31
...
For example:
void f(int n)
{
vector∗ p = new vector(n);
// individual object
int∗ q = new int[n];
// array
//
...
2
...
Applying delete[] to the null pointer has no effect
...
For example:
void f1()
{
X∗ p =new X;
//
...

delete p;
}

That’s verbose, inefficient, and error-prone (§13
...
In particular, a return or an exception thrown
before the delete will cause a memory leak (unless even more code is added)
...
use x
...


11
...
3 Getting Memory Space
The free-store operators
in the header:

new, delete, new[],

void∗ operator new(size_t);
void operator delete(void∗ p);

and

delete[]

are implemented using functions presented

// allocate space for individual object
// if (p) deallocate space allocated using operator new()

Section 11
...
3

void∗ operator new[](size_t);
void operator delete[](void∗ p);

Getting Memory Space

283

// allocate space for array
// if (p) deallocate space allocated using operator new[]()

When operator new needs to allocate space for an object, it calls operator new() to allocate a suitable
number of bytes
...

The standard implementations of operator new() and operator new[]() do not initialize the memory returned
...
Consequently, they take arguments or return
values of type void∗
...

What happens when new can find no store to allocate? By default, the allocator throws a standard-library bad_alloc exception (for an alternative, see §11
...
4
...
For example:
void f()
{
vector v;
try {
for (;;) {
char ∗ p = new char[10000];
v
...
Please
be careful: the new operator is not guaranteed to throw when you run out of physical main memory
...

We can specify what new should do upon memory exhaustion; see §30
...
1
...

In addition to the functions defined in , a user can define operator new(), etc
...
2
...
Class members operator new(), etc
...


11
...
4 Overloading new
By default, operator new creates its object on the free store
...

};

284

Select Operations

Chapter 11

We can place objects anywhere by providing an allocator function (§11
...
3) with extra arguments
and then supplying such extra arguments when using new:
void∗ operator new(size_t, void∗ p) { return p; }

// explicit placement operator

void∗ buf = reinterpret_cast(0xF00F);
X∗ p2 = new(buf) X;

// significant address
// construct an X at buf;
// invokes: operator new(sizeof(X),buf)

Because of this usage, the new(buf) X syntax for supplying extra arguments to operator new() is
known as the placement syntax
...
2
...
The operator new() used by the
new operator is chosen by the usual argument matching rules (§12
...

The ‘‘placement’’ operator new() is the simplest such allocator
...
5)
...

};
void∗ operator new(size_t sz, Arena∗ a)
{
return a−>alloc(sz);
}

Now objects of arbitrary types can be allocated from different Arenas as needed
...

}

// X in persistent storage
// X in shared memory

Section 11
...
4

Overloading new

285

Placing an object in an area that is not (directly) controlled by the standard free-store manager
implies that some care is required when destroying the object
...
Even most resource handles can be written using new and delete
...
4
...
3
...
A novice should think thrice before
calling a destructor explicitly and also should ask a more experienced colleague before doing so
...
6
...

There is no special syntax for placement of arrays
...
However, an operator delete() can be defined for arrays (§11
...
3)
...
2
...
1 nothrow new
In programs where exceptions must be avoided (§13
...
5), we can use
delete
...
handle allocation error
...

operator delete(nothrow,p);
// deallocate *p
}

That nothrow is the name of an object of the standard-library type nothrow_t that is used for disambiguation; nothrow and nothrow_t are declared in
...


286

Select Operations

Chapter 11

11
...
3
...
2), {}-lists can be used as expressions
in many (but not all) places
...
}, meaning ‘‘create an object of type T initialized by T{
...
3
...
}, for which the the type must be determined from the context of use;
§11
...
3
For example:
struct S { int a, b; };
struct SS { double a, b; };
void f(S);

// f() takes an S

void g(S);
void g(SS);

// g() is overloaded

void h()
{
f({1,2});
g({1,2});
g(S{1,2});
g(SS{1,2});

// OK: call f(S{1,2})
// error : ambiguous
// OK: call g(S)
// OK: call g(SS)

}

As in their use for initializing named variables (§6
...
5), lists can have zero, one, or more elements
...


11
...
1 Implementation Model
The implementation model for {}-lists comes in three parts:
• If the {}-list is used as constructor arguments, the implementation is just as if you had used a
()-list
...

• If the {}-list is used to initialize the elements of an aggregate (an array or a class without a
constructor), each list element initializes an element of the aggregate
...

• If the {}-list is used to construct an initializer_list object each list element is used to initialize
an element of the underlying array of the initializer_list
...

Note that this is the general model that we can use to understand the semantics of a {}-list; a compiler may apply clever optimizations as long as the meaning is preserved
...
14};

The standard-library

vector

has an initializer-list constructor (§17
...
4), so the initializer list

Section 11
...
1

{1,2,3
...
14 } ;
const initializer_list tmp(temp,sizeof(temp)/sizeof(double));
vector v(tmp);

That is, the compiler constructs an array containing the initializers converted to the desired type
(here, double)
...
The
initializer-list constructor then copies the values from the array into its own data structure for elements
...

The underlying array is immutable, so there is no way (within the standard’s rules) that the
meaning of a {}-list can change between two uses
...
begin() << '\n';
∗lst
...
begin() << '\n';
}

In particular, having a {}-list be immutable implies that a container taking elements from it must use
a copy operation, rather than a move operation
...
4
...
When used to initialize a variable of type initializer_list, the list lives as long as the
variable
...


11
...
2 Qualified Lists
The basic idea of initializer lists as expressions is that if you can initialize a variable
notation

x

using the

T x {v};

then you can create an object with the same value as an expression using T{v} or new T{v}
...
4
...
For example:
struct S { int a, b; };
void f()
{
S v {7,8};
v = S{7,8};
S∗ p = new S{7,8};
}

// direct initialization of a variable
// assign using qualified list
// construct on free store using qualified list

The rules constructing an object using a qualified list are those of direct initialization (§16
...
6)
...
For example:
template
T square(T x)
{
return x∗x;
}
void f(int i)
{
double d = square(double{i});
complex z = square(complex{i});
}

That idea is explored further in §11
...
1
...
3
...
It can be used as an
expression only as:
• A function argument
• A return value
• The right-hand operand of an assignment operator (=, +=, ∗=, etc
...
0});
return {11};

// right-hand operand of assignment
// right-hand operand of assignment
// error: not left-hand operand of assignment
// error: not an operand of a non-assignment operator
// function argument
// return value

}

The reason that an unqualified list is not allowed on the left-hand side of assignments is primarily
that the C++ grammar allows { in that position for compound statements (blocks), so that readability would be a problem for humans and ambiguity resolution would be tricky for compilers
...

When used as the initializer for a named object without the use of a = (as for v above), an
unqualified {}-list performs direct initialization (§16
...
6)
...
2
...
In particular, the otherwise redundant = in an initializer restricts the set of
initializations that can be performed with a given {}-list
...
3
...
2
...

Its most obvious use is to allow initializer lists for user-defined containers (§3
...
1
...
size()==0) return high;
for (auto x : val)
if (x>high) high = x;
return high;
}
int v1 = high_value({1,2,3,4,5,6,7});
int v2 = high_value({−1,2,v1,4,−9,20,v1});

A {}-list is the simplest way of dealing with homogeneous lists of varying lengths
...
If so, that case should be handled by a default constructor (§17
...
3)
...
For example:
auto x0 = {};
auto x1 = {1};
auto x2 = {1,2};
auto x3 = {1,2,3};
auto x4 = {1,2
...
For
example:
template
void f(T);
f({});
f({1});
f({1,2});
f({1,2,3});

// error: type of initializer is unknown
// error: an unqualified list does not match ‘‘plain T’’
// error: an unqualified list does not match ‘‘plain T’’
// error: an unqualified list does not match ‘‘plain T’’

I say ‘‘unfortunately’’ because this is a language restriction, rather than a fundamental rule
...

Similarly, we do not deduce the element type of a container represented as a template
...
To deduce T the compiler would first have to decide that
the user really wanted a vector and then look into the definition of vector to see if it has a constructor that accepts {1,2,3}
...
2)
...
To call f2(), be
more specific:
f2(vector{1,2,3});
f2(vector{"Kona","Sidney"});

// OK
// OK

11
...
Instead of defining a named class with an operator(), later making an object of that
class, and finally invoking it, we can use a shorthand
...
In the context of graphical user interfaces (and
elsewhere), such operations are often referred to as callbacks
...
4
...
4, §33
...
2)
...
The capture list is delimited by [] (§11
...
3)
...
The
parameter list is delimited by () (§11
...
4)
...
e
...
4
...
4)
...

• An optional return type declaration of the form −> type (§11
...
4)
...
The body is delimited by {} (§11
...
3)
...
The notion of ‘‘capture’’ of local variables is not provided for
functions
...


11
...
1 Implementation Model
Lambda expressions can be implemented in a variety of ways, and there are some rather effective
ways of optimizing them
...
Consider a relatively simple
example:

Section 11
...
1

Implementation Model

291

void print_modulo(const vector& v, ostream& os, int m)
// output v[i] to os if v[i]%m==0
{
for_each(begin(v),end(v),
[&os,m](int x) { if (x%m==0) os << x << '\n'; }
);
}

To see what this means, we can define the equivalent function object:
class Modulo_print {
ostream& os; // members to hold the capture list
int m;
public:
Modulo_print(ostream& s, int mm) :os(s), m(mm) {}
void operator()(int x) const
{ if (x%m==0) os << x << '\n'; }
};

// capture

The capture list, [&os,m], becomes two member variables and a constructor to initialize them
...
This use of & mirrors its use in function argument declarations
...
Since the lambda doesn’t
return a value, the operator()() is void
...
That’s by far the most common case
...
4
...
4)
...

An object of a class generated from a lambda is called a closure object (or simply a closure)
...


[&]),

the

11
...
2 Alternatives to Lambdas
That final version of print_modulo() is actually quite attractive, and naming nontrivial operations is
generally a good idea
...

However, many lambdas are small and used only once
...
For example:

292

Select Operations

void print_modulo(const vector& v, ostream& os, int m)
// output v[i] to os if v[i]%m==0
{
class Modulo_print {
ostream& os; // members to hold the capture list
int m;
public:
Modulo_print (ostream& s, int mm) :os(s), m(mm) {}
void operator()(int x) const
{ if (x%m==0) os << x << '\n'; }
};

Chapter 11

// capture

for_each(begin(v),end(v),Modulo_print{os,m});
}

Compared to that, the version using the lambda is a clear winner
...
Doing so forces us to consider the design of the operation
a bit more carefully
...
4
...

Writing a for-loop is an alternative to using a lambda with a for_each()
...
However, for_each is a
rather special algorithm, and vector is a very specific container
...
The C++ range-for-statement specifically caters to the special
case of traversing a sequence from its beginning to its end
...
4
...
For example, using a for-statement to traverse a map gives a depth-first
traversal
...
For example:
template
void print_modulo(const C& v, ostream& os, int m)
// output v[i] to os if v[i]%m==0
{
breadth_first(begin(v),end(v),
[&os,m](int x) { if (x%m==0) os << x << '\n'; }
);
}

Thus, a lambda can be used as ‘‘the body’’ for a generalized loop/traversal construct represented as
an algorithm
...

The performance of a lambda as an argument to a traversal algorithm is equivalent (typically
identical) to that of the equivalent loop
...
The implication is that we have to base our choice between ‘‘algorithm plus
lambda’’ and ‘‘for-statement with body’’ on stylistic grounds and on estimates of extensibility and
maintainability
...
4
...
Lambdas allow that to
be done ‘‘inline’’ without having to name a function (or function object) and use it elsewhere
...
Such lambdas are defined with the
empty lambda introducer []
...
begin(),v
...

sort(v
...
end(),[](int x, int y) { return abs(x)//
...

sort(v
...
end(),
[](int x, int y) { return sensitive ? x);
}

// error : can’t access sensitive

I used the lambda introducer []
...
The first character of a lambda expression is
always [
...
This implies that no local names from the surrounding context can
be used in the lambda body
...

• [&]: implicitly capture by reference
...
All local variables are
accessed by reference
...
All local names can be used
...

• [capture-list]: explicit capture; the capture-list is the list of names of local variables to be
captured (i
...
, stored in the object) by reference or by value
...
Other variables are captured by value
...
as elements
...
The capture list can contain this
...

Variables named in the capture list are captured by value
...
The capture list cannot contain this
...
Variables named in the capture list are captured by reference
...
Only capture by reference allows modification of variables
in the calling environment
...
For example:
void f(vector& v)
{
bool sensitive = true;
//
...
begin(),v
...
By not
specifying otherwise, we ensure that the capture of sensitive is done ‘‘by value’’; just as for argument passing, passing a copy is the default
...

The choice between capturing by value and by reference is basically the same as the choice for
function arguments (§12
...
We use a reference if we need to write to the captured object or if it is
large
...
4
...
1)
...

If you need to capture a variadic template (§28
...
For example:

Section 11
...
3

Capture

295

template ...
v)
{
auto helper = [&s,&v
...
)+h2(v
...

}

Beware that is it easy to get too clever about capture
...
When that’s the case, capture is usually the least typing but has the greatest
potential for confusion
...
4
...
1 Lambda and Lifetime
A lambda might outlive its caller
...
For example:
void setup(Menu& m)
{
//
...
add("draw triangle",[&]{ m
...

}

// probable disaster

Assuming that add() is an operation that adds a (name,action) pair to a menu and that the draw()
operation makes sense, we are left with a time bomb: the setup() completes and later – maybe minutes later – a user presses the draw triangle button and the lambda tries to access the long-gone local
variables
...

If a lambda might outlive its caller, we must make sure that all local information (if any) is
copied into the closure object and that values are returned through the return mechanism (§12
...
4)
or through suitable arguments
...
add("draw triangle",[=]{ m
...
4
...


[=]

and

[&]

as short-hand

11
...
3
...
For example:
template
ostream& operator<<(ostream& os, const pair& p)
{
return os << '{' << p
...
second << '}';
}

296

Select Operations

Chapter 11

void print_all(const map& m, const string& label)
{
cout << label << ":\n{\n";
for_each(m
...
end(),
[](const pair& p) { cout << p << '\n'; }
);
cout << "}\n";
}

Here, we don’t need to capture cout or the output operator for pair
...
4
...
3 Lambda and this
How do we access members of a class object from a lambda used in a member function? We can
include class members in the set of names potentially captured by adding this to the capture list
...
For
example, we might have a class for building up requests and retrieving results:
class Request {
function(const map&)> oper;
map values;
// arguments
map results;
// targets
public:
Request(const string& s);
// parse and store request
void execute()
{
[this]() { results=oper(values); }
}

// operation

// do oper to values yielding results

};

Members are always captured by reference
...
Unfortunately, [this] and [=] are incompatible
...
4
...


11
...
3
...
That is, the operator()() for the generated function object (§11
...
1) is a const member function
...
4
...
For example:
void algo(vector& v)
{
int count = v
...
begin(),v
...


Section 11
...
4

Call and Return

297

11
...
4 Call and Return
The rules for passing arguments to a lambda are the same as for a function (§12
...
1
...
In fact, with the exception of the rules for capture (§11
...
3)
most rules for lambdas are borrowed from the rules for functions and classes
...

Thus, the minimal lambda expression is []{}
...
Unfortunately, that is
not also done for a function
...
If a lambda
body consists of just a single return-statement, the lambda’s return type is the type of the return’s
expression
...
For example:
void g(double y)
{
[&]{ f(y); }
auto z1 = [=](int x){ return x+y; }
auto z2 = [=,y]{ if (y) return 1; else return 2; }
auto z3 =[y]() { return 1 : 2; }
auto z4 = [=,y]()−>int { if (y) return 1; else return 2; }

// return type is void
// return type is double
// error : body too complicated
// for return type deduction
// return type is int
// OK: explicit return type

}

When the suffix return type notation is used, we cannot omit the argument list
...
4
...
However, it is defined to be the type of a function object in the style presented in §11
...
1
...

Had two lambdas had the same type, the template instantiation mechanism might have gotten confused
...
In addition to using a lambda as an argument, we can use it to initialize a variable declared
auto or std::function where R is the lambda’s return type and AL is its argument list of types
(§33
...
3)
...

Instead, I can introduce a name and then use it:
void f(string& s1, string& s2)
{
function rev =
[&](char∗ b, char∗ e) { if (1
298

Select Operations

Chapter 11

rev(&s1[0],&s1[0]+s1
...
size());
}

Now, the type of rev is specified before it is used
...
size());
rev(&s2[0],&s2[0]+s2
...
For
example:
double (∗p1)(double) = [](double a) { return sqrt(a); };
double (∗p2)(double) = [&](double a) { return sqrt(a); };
double (∗p3)(int) = [](int a) { return sqrt(a); };

// error : the lambda captures
// error : argument types do not match

11
...
Many (arguably too
many) such conversions are done implicitly according to the language rules (§2
...
2, §10
...
For
example:
double d = 1234567890; // integer to floating-point
int i = d;
// floating-point to integer

In other cases, we have to be explicit
...
5
...
5)
• static_cast for reversing a well-defined implicit conversion (§11
...
2)
• reinterpret_cast for changing the meaning of bit patterns (§11
...
2)
• dynamic_cast for dynamically checked class hierarchy navigation (§22
...
1)
• C-style casts, providing any of the named conversions and some combinations of those
(§11
...
3)
• Functional notation, providing a different notation for C-style casts (§11
...
4)
I have ordered these conversions in my order of preference and safety of use
...
For conversion between two scalar numeric types, I tend to use a homemade
explicit conversion function, narrow_cast, where a value might be narrowed:

Section 11
...
That is a generalization of the rule the language
applies to values in {} initialization (§6
...
5
...
For example:
void test(double d, int i, char∗ p)
{
auto c1 = narrow_cast(64);
auto c2 = narrow_cast(−64);
auto c3 = narrow_cast(264);

// will throw if chars are unsigned
// will throw if chars are 8-bit and signed

auto d1 = narrow_cast(1/3
...
0);
// will probably throw
auto c4 = narrow_cast(i);
auto f2 = narrow_cast<float>(d);

// may throw
// may throw

auto p1 = narrow_cast(i);
auto i1 = narrow_cast(p);

// compile-time error
// compile-time error

auto d2 = narrow_cast(i);
auto i2 = narrow_cast(d);

// may throw (but probably will not)
// may throw

}

Depending on your use of floating-point numbers, it may be worthwhile to use a range test for
floating-point conversions, rather than !=
...
3
...
1) or
type traits (§35
...
1)
...
5
...
8
...
4)
...
0
// d1==0
...


300

Select Operations

Chapter 11

void f(int);
void f(double);
void g(int i, double d)
{
f(i);
f(double{i});

// call f(int)
// error : {} doesn’t do int to floating conversion

f(d);
f(int{d});
f(static_cast(d));

// call f(double)
// error : {} doesn’t truncate
// call f(int) with a truncated value

f(round(d));
// call f(double) with a rounded value
f(static_cast(lround(d))); // call f(int) with a rounded value
// if the d is overflows the int, this still truncates
}

I don’t consider truncation of floating-point numbers (e
...
, 7
...
If rounding is desirable, we can use the standardlibrary function round(); it performs ‘‘conventional 4/5 rounding,’’ such as 7
...
4 to 7
...
Consider:
static_assert(sizeof(int)==sizeof(double),"unexpected sizes");
int x = numeric_limits::max(); // largest possible integer
double d = x;
int y = x;

We will not get x==y
...
For example:
double d { 1234 };

double

with an integer literal that can be

// fine

Explicit qualification with the desired type does not enable ill-behaved conversions
...

}

// error: no char* to int conversion
// error: no char* to int* conversion

For T{v}, ‘‘reasonably well behaved’’ is defined as having a ‘‘non-narrowing’’ (§10
...
3)
...
For example:

Section 11
...
1

Construction

301

template void f(const T&);
void g3()
{
f(int{});
f(complex{});
//
...
3
...

Thus, int{} is another way of writing 0
...
2
...
1, §17
...

Explicitly constructed unnamed objects are temporary objects, and (unless bound to a reference)
their lifetime is limited to the full expression in which they are used (§6
...
2)
...
2)
...
5
...
For example:
IO_device∗ d1 = reinterpret_cast(0Xff00); // device at 0Xff00

There is no way a compiler can know whether the integer 0Xff00 is a valid address (of an I/O device
register)
...
Explicit type conversion, often called casting, is occasionally essential
...

Another classical example of the need for explicit type conversion is dealing with ‘‘raw memory,’’ that is, memory that holds or will hold objects of a type not known to the compiler
...
2
...

}

// new allocation used as ints

A compiler does not know the type of the object pointed to by the void∗
...
It also does conversions defined by constructors (§16
...
6, §18
...
3, §iso
...
2
...
4)
...
5
...
10)
...
5
...
11)
...
2
...
5
...
7)
...
Some static_casts are portable, but few reinterpret_casts are
...
If the target has at least as many bits as the original value, we can reinterpret_cast the result back to its original type and use it
...
Note that reinterpret_cast
is the kind of conversion that must be used for pointers to functions (§12
...
Consider:
char x = 'a';
int∗ p1 = &x;
int∗ p2 = static_cast(&x);
int∗ p3 = reinterpret_cast(&x);

// error : no implicit char* to int* conversion
// error : no implicit char* to int* conversion
// OK: on your head be it

struct B { /*
...
*/ };

// see §3
...
2 and §20
...
2

B∗ pb = new D;
D∗ pd = pb;
D∗ pd = static_cast(pb);

// OK: implicit conversion from D* to B*
// error : no implicit conversion from B* to D*
// OK

Conversions among class pointers and among class reference types are discussed in §22
...

If you feel tempted to use an explicit type conversion, take the time to consider if it is really
necessary
...
3
...
3
...
2
...
In many programs, explicit type conversion can be completely avoided; in others, its use can be localized to a
few routines
...
5
...
2
...
Unfortunately, the C-style cast can also cast from a pointer to a class to a
pointer to a private base of that class
...
This C-style cast is far more dangerous than the named conversion operators
because the notation is harder to spot in a large program and the kind of conversion intended by the
programmer is not explicit
...
Without knowing the exact types of T and e, you cannot tell
...
5
...
5
...
For example:

T

from a value

e

can be expressed by the functional notation

void f(double d)
{
int i = int(d);
// truncate d
complex z = complex(d); // make a complex from d
//
...
Unfortunately, for a built-in
type T, T(e) is equivalent to (T)e (§11
...
3)
...

void f(double d, char∗ p)
{
int a = int(d); // truncates
int b = int(p); // not portable
//
...

Prefer T{v} conversions for well-behaved construction and the named casts (e
...
, static_cast) for
other conversions
...
6 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]
[14]

Prefer prefix ++ over suffix ++; §11
...
4
...
2
...

Don’t put objects on the free store if you don’t have to; prefer scoped variables; §11
...
1
...
2
...

Use RAII; §11
...
1
...
4
...

Prefer a named function object to a lambda if the operation is generally useful; §11
...
2
...
4
...

For maintainability and correctness, be careful about capture by reference; §11
...
3
...

Let the compiler deduce the return type of a lambda; §11
...
4
...
5
...

Avoid explicit type conversion (casts); §11
...

When explicit type conversion is necessary, prefer a named cast; §11
...

Consider using a run-time checked cast, such as narrow_cast<>(), for conversion between
numeric types; §11
...


This page intentionally left blank

12
Functions
Death to all fanatics!
– Paradox












Function Declarations
Why Functions?; Parts of a Function Declaration; Function Definitions; Returning Values;
inline Functions; constexpr Functions; [[noreturn]] Functions; Local Variables
Argument Passing
Reference Arguments; Array Arguments; List Arguments; Unspecified Number of Arguments; Default Arguments
Overloaded Functions
Automatic Overload Resolution; Overloading and Return Type; Overloading and Scope;
Resolution for Multiple Arguments; Manual Overload Resolution
Pre- and Postconditions
Pointer to Function
Macros
Conditional Compilation; Predefined Macros; Pragmas
Advice

12
...
Defining a
function is the way you specify how an operation is to be done
...

A function declaration gives the name of the function, the type of the value returned (if any),
and the number and types of the arguments that must be supplied in a call
...
2
...

Argument types are checked and implicit argument type conversion takes place when necessary
...

A function declaration may contain argument names
...
As a return type, void means that the function does not return a value (§6
...
7)
...
For class member
functions (§2
...
2, §16
...
For example:
double f(int i, const Info&);
char& String::operator[](int);

// type: double(int,const Info&)
// type: char& String::(int)

12
...
1 Why Functions?
There is a long and disreputable tradition of writing very long functions – hundreds of lines long
...
Writers of
such functions seem to fail to appreciate one of the primary purposes of functions: to break up complicated computations into meaningful chunks and name them
...
The first step to comprehensibility is to break computational tasks into comprehensible chunks (represented as functions and
classes) and name those
...
The C++ standard algorithms (e
...
, find, sort, and iota) provide a good start (Chapter 32)
...

The number of errors in code correlates strongly with the amount of code and the complexity of
the code
...
Using a function
to do a specific task often saves us from writing a specific piece of code in the middle of other code;
making it a function forces us to name the activity and document its dependencies
...
6) and continues (§9
...
5)
...
g
...
6)
...
Bugs tend to creep in when we can view only part of an algorithm at a time
...
My ideal is a much smaller size still,
maybe an average of 7 lines
...
Where that cost
could be significant (e
...
, for frequently used access functions, such as vector subscripting) inlining
can eliminate it (§12
...
5)
...


Section 12
...
2

Parts of a Function Declaration

307

12
...
2 Parts of a Function Declaration
In addition to specifying a name, a set of arguments, and a return type, a function declaration can
contain a variety of specifiers and modifiers
...
1
...
1
...
5
...
1)
• A linkage specification, for example, static (§15
...
1
...
3
...
3
...
1)
• final, indicating that it cannot be overriden in a derived class (§20
...
4
...
2
...
2
...
1, §16
...
9
...
1
...
2
...
A function definition is a function declaration in which the body of the function is presented
...
Unfortunately, to preserve C compatibility, a const is ignored at the highest level of an argument type
...

Function argument names are not part of the function type and need not be identical in different
declarations
...
Conversely, we can indicate that an argument is unused in a function definition by not naming it
...
In both cases, leaving the argument in place, although unused, ensures that callers are
not affected by the change
...
2):
• Constructors (§2
...
2, §16
...
5) are technicallly not functions; in particular, they don’t return
a value, can initialize bases and members (§17
...

• Destructors (§3
...
1
...
2) can’t be overloaded and can’t have their address taken
...
4
...
2
...

• Lambda expressions (§3
...
3, §11
...


12
...
4 Returning Values
Every function declaration contains a specification of the function’s return type (except for constructors and type conversion functions)
...
However, a function declaration can also
be written using a syntax that places the return type after the argument list
...
1
...
The suffix
return type is preceded by −>
...
For example:
template
auto product(const vector& x, const vector& y) −> decltype(x∗y);

However, the suffix return syntax can be used for any function
...
4
...
4); it
is a pity those two constructs are not identical
...

A value must be returned from a function that is not declared void (however, main() is special;
see §2
...
1)
...
For example:
int f1() { }
void f2() { }

// error: no value returned
// OK

int f3() { return 1; }
void f4() { return 1; }

// OK
// error : return value in void function

int f5() { return; }
void f6() { return; }

// error : return value missing
// OK

A return value is specified by a return-statement
...

There can be more than one return-statement in a function:
int fac2(int n)
{
if (n > 1)
return n∗fac2(n−1);
return 1;
}

Like the semantics of argument passing, the semantics of function value return are identical to the
semantics of copy initialization (§16
...
6)
...
The type of a return expression is checked against the type of the returned type, and all standard and user-defined type conversions are performed
...
The store is reused after the function returns, so a pointer to a local non-static variable should
never be returned
...

return &local; // bad
}

An equivalent error can occur when using references:
int& fr()
{
int local = 1;
//
...

There are no void values
...
For example:
void g(int∗ p);
void h(int∗ p)
{
//
...

A return-statement is one of five ways of exiting a function:
• Executing a return-statement
...

This is allowed only in functions that are not declared to return a value (i
...
, void functions)
and in main(), where falling off the end indicates successful completion (§12
...
4)
...
5)
...
5
...
1)
...
g
...
4)
...
e
...
1
...


12
...
5 inline Functions
A function can be defined to be inline
...
1
...
A clever compiler can generate the constant 720 for a call fac(6)
...
, makes it impossible to guarantee that every call of an inline function is actually inlined
...
If you want a guarantee that a value is
computed at compile time, declare it constexpr and make sure that all functions used in its evaluation are constexpr (§12
...
6)
...
2)
...
In particular, an inline function still has
a unique address, and so do static variables (§12
...
8) of an inline function
...
g
...
2
...
2
...


12
...
6 constexpr Functions
In general, a function cannot be evaluated at compile time and therefore cannot be called in a constant expression (§2
...
3, §10
...
By specifying a function constexpr, we indicate that we want it to
be usable in constant expressions if given constant expressions as arguments
...
’’ When used in an object definition, it means
‘‘evaluate the initializer at compile time
...

}

To be evaluated at compile time, a function must be suitably simple: a

constexpr

function must

312

Functions

Chapter 12

consist of a single return-statement; no loops and no local variables are allowed
...
That is, a constexpr function is a pure function
...
4
...

A constexpr function allows recursion and conditional expressions
...
However, you’ll find the
debugging gets unnecessarily difficult and compile times longer than you would like unless you
restrict the use of constexpr functions to the relatively simple tasks for which they are intended
...
4
...

Like inline functions, constexpr functions obey the ODR (‘‘one-definition rule’’), so that definitions in the different translation units must be identical (§15
...
3)
...
1
...


12
...
6
...
However, a constexpr function can refer to nonlocal objects as long as it does not write to them
...
Of course, it cannot write through such references, but const reference parameters are as useful as ever
...
4) we find:

Section 12
...
6
...

explicit constexpr complex(const complex&);
//
...
0};

The temporary variable that is logically constructed to hold the const reference argument simply
becomes a value internal to the compiler
...
For example:
constexpr const int∗ addr(const int& r) { return &r; }

// OK

However, doing so brings us away from the fundamental role of constexpr functions as parts of constant expression evaluation
...
Consider:
static const int x = 5;
constexpr const int∗ p1 = addr(x);
constexpr int xx = ∗p1;

// OK
// OK

static int y;
constexpr const int∗ p2 = addr(y);
constexpr int yy = ∗y;

// OK
// error : attempt to read a variable

constexpr const int∗ tp = addr(5);

// error : address of temporar y

12
...
6
...
This
implies that a branch not taken can require run-time evaluation
...

constexpr int val = check(f(x,y,z));

You might imagine low and high to be configuration parameters that are known at compile time, but
not at design time, and that f(x,y,z) computes some implementation-dependent value
...
1
...
]] is called an attribute and can be placed just about anywhere in the C++ syntax
...
In addition, an attribute can be placed in front of a declaration
...
7
...
The other is [[carries_dependency]] (§41
...

Placing [[noreturn]] at the start of a function declaration indicates that the function is not
expected to return
...

What happens if the function returns despite a [[noreturn]] attribute is undefined
...
1
...
A local variable or constant
is initialized when a thread of execution reaches its definition
...
If a local variable is declared static, a single,
statically allocated object (§6
...
2) will be used to represent that variable in all calls of the function
...
For example:
void f(int a)
{
while (a−−) {
static int n = 0;
int x = 0;

// initialized once
// initialized ’a’ times in each call of f()

cout << "n == " << n++ << ", x == " << x++ << '\n';
}
}
int main()
{
f(3);
}

This prints:
n == 0, x == 0
n == 1, x == 0
n == 2, x == 0

A static local variable allows the function to preserve information between calls without introducing a global variable that might be accessed and corrupted by other functions (see also §16
...
12)
...
3
...
6
...
That is, the C++ implementation
must guard the initialization of a local static variable with some kind of lock-free construct (e
...
, a
call_once; §42
...
3)
...
For example:

Section 12
...
8

int fn(int n)
{
static int n1 = n;
static int n2 = fn(n−1)+1;
return n;
}

Local Variables

315

// OK
// undefined

A static local variable is useful for avoiding order dependencies among nonlocal variables
(§15
...
1)
...
4
...
4)
...
6), should you be foolhardy enough to use one, is the complete function, independent of which nested scope it may be in
...
2 Argument Passing
When a function is called (using the suffix (), known as the call operator or application operator),
store is set aside for its formal arguments (also known as its parameters), and each formal argument is initialized by its corresponding actual argument
...
2
...
In particular,
the type of an actual argument is checked against the type of the corresponding formal argument,
and all standard and user-defined type conversions are performed
...
For example:
int∗ find(int∗ first, int∗ last, int v)
// find x in [first:last)
{
while (first!=last && ∗first!=v)
++first;
return first;
}
void g(int∗ p, int∗ q)
{
int∗ pp = find(p,q,'x');
//
...
The pointer is passed by value
...
2
...
2
...
2
...
The use of initializer lists is
described in §12
...
3 and the ways of passing arguments to template functions in §23
...
2 and
§28
...
2
...
2
...
Consider:

++ref

incre-

void g()
{
int i = 1;
int j = 1;
f(i,j);
}

The call f(i,j) will increment j but not i
...
As mentioned in §7
...
2
...
It can,
however, be noticeably more efficient to pass a large object by reference than to pass it by value
...
5)
}

The absence of const in the declaration of a reference argument is taken as a statement of intent to
modify the variable:
void g(Large& arg);

// assume that g() modifies arg

Similarly, declaring a pointer argument const tells readers that the value of an object pointed to by
that argument is not changed by the function
...

Note that the semantics of argument passing are different from the semantics of assignment
...

Following the rules for reference initialization, a literal, a constant, and an argument that
requires conversion can be passed as a const T& argument, but not as a plain (non-const) T& argument
...
2
...


float fsqrt(const float&); // Fortran-style sqrt taking a reference argument
void g(double d)
{
float r = fsqrt(2
...
0f
// pass reference to r
// pass reference to temp holding static_cast<float>(d)

Disallowing conversions for non-const reference arguments (§7
...
For example:
void update(float& i);
void g(double d, float r)
{
update(2
...
Usually, that would come as an unpleasant surprise to the programmer
...
As described in §7
...
For example:
void f(vector&);
void f(const vector&);
void f(vector&&);

// (non-const) lvalue reference argument
// const lvalue reference argument
// rvalue reference argument

void g(vector& vi, const vector& cvi)
{
f(vi);
// call f(vector&)
f(vci);
// call f(const vector&)
f(vector{1,2,3,4}); // call f(vector&&);
}

We must assume that a function will modify an rvalue argument, leaving it good only for destruction or reassignment (§17
...
The most obvious use of rvalue references is to define move
constructors and move assignments (§3
...
2, §17
...
2)
...

Please note that for a template argument T, the template argument type deduction rules give T&&
a significantly different meaning from X&& for a type X (§23
...
2
...
For template arguments, an
rvalue reference is most often used to implement ‘‘perfect forwarding’’ (§23
...
2
...
6
...


318

Functions

Chapter 12

How do we choose among the ways of passing arguments? My rules of thumb are:
[1] Use pass-by-value for small objects
...

[3] Return a result as a return value rather than modifying an object through an argument
...
3
...
5
...
5
...
1)
...

[6] Use pass-by-reference only if you have to
...
7
...
7
...


12
...
2 Array Arguments
If an array is used as a function argument, a pointer to its initial element is passed
...
This implies
that an assignment to an element of an array argument changes the value of an element of the argument array
...

Instead, a pointer is passed (by value)
...
For example:
void odd(int∗ p);
void odd(int a[]);
void odd(int buf[1020]);

These three declarations are equivalent and declare the same function
...
1
...
The rules and techniques for passing multidimensional arrays can be found in §7
...
3
...
This is a major source of errors, but
there are several ways of circumventing this problem
...
g
...
4)
...
For example:
void compute1(int∗ vec_ptr, int vec_size);

// one way

At best, this is a workaround
...
4
...
4), array (§34
...
1), or map (§4
...
3, §31
...
3)
...
For example:

Section 12
...
2

Array Arguments

319

void f(int(&r)[4]);
void g()
{
int a1[] = {1,2,3,4};
int a2[] = {1,2};
f(a1);
f(a2);

// OK
// error : wrong number of elements

}

Note that the number of elements is part of a reference-to-array type
...
The main use of references to arrays
is in templates, where the number of elements is then deduced
...

}
int a1[10];
double a2[100];
void g()
{
f(a1);
f(a2);
}

// T is int; N is 10
// T is double; N is 100

This typically gives rise to as many function definitions as there are calls to f() with distinct array
types
...
3), but often arrays of pointers can be used instead,
and they need no special treatment
...


12
...
3 List Arguments
A {}-delimited list can be used as an argument to a parameter of:
[1] Type std::initializer_list, where the values of the list can be implicitly converted to T
[2] A type that can be initialized with the values provided in the list
[3] A reference to an array of T, where the values of the list can be implicitly converted to T
Technically, case [2] covers all examples, but I find it easier to think of the three cases separately
...
For example:
template
void f(initializer_list);
struct S {
int a;
string s;
};
void f(S);
template
void f(T (&r)[N]);
void f(int);
void g()
{
f({1,2,3,4});
f({1,"MKS"});
f({1});
}

// T is int and the initializer_list has size() 4
// calls f(S)
// T is int and the initializer_list has size() 1

The reason that a function with an initializer_list argument take priority is that it could be very confusing if different functions were chosen based on the number of elements of a list
...
4, §17
...
4
...


Section 12
...
3

List Arguments

321

If there is a function with an initializer-list argument in scope, but the argument list isn’t a
match for that, another function can be chosen
...

Note that these rules apply to std::initializer_list arguments only
...


12
...
4 Unspecified Number of Arguments
For some functions, it is not possible to specify the number and type of all arguments expected in a
call
...
6): this allows us to handle an arbitrary number of arbitrary
types in a type-safe manner by writing a small template metaprogram that interprets the
argument list to determine its meaning and take appropriate actions
...
2
...
This allows us to handle an arbitrary
number of arguments of a single type in a type-safe manner
...

[3] Terminate the argument list with the ellipsis (
...
’’ This allows us to handle an arbitrary number of (almost) arbitrary types by
using some macros from
...
However, this mechanism has been
used from the earliest days of C
...
For example:
int printf(const char∗
...
3) must have at least one argument, a C-style string, but may or may not have others
...
In the case of printf(), the first argument is a format string containing special character
sequences that allow printf() to handle other arguments correctly; %s means ‘‘expect a char∗ argument’’ and %d means ‘‘expect an int argument
...

For example:
#include
int main()
{
std::printf("My name is %s %s\n",2);
}

This is not valid code, but most compilers will not catch this error
...


322

Functions

Chapter 12

Clearly, if an argument has not been declared, the compiler does not have the information
needed to perform the standard type checking and type conversion for it
...
This is not necessarily what the programmer expects
...
Overloaded functions, functions using default arguments, functions taking
initializer_list arguments, and variadic templates can be used to take care of type checking in most
cases when one would otherwise consider leaving argument types unspecified
...

The most common use of the ellipsis is to specify an interface to C library functions that were
defined before C++ provided alternatives:
int fprintf(FILE∗, const char∗
...
);

// from
// from UNIX header

A standard set of macros for accessing the unspecified arguments in such functions can be found in

...
The idea is to compose the error message by passing each word as a separate C-style string argument
...
);
extern char∗ itoa(int, char[]); // int to alpha
int main(int argc, char∗ argv[])
{
switch (argc) {
case 1:
error(0,argv[0],nullptr);
break;
case 2:
error(0,argv[0],argv[1],nullptr);
break;
default:
char buffer[8];
error(1,argv[0],"with",itoa(argc−1,buffer),"arguments",nullptr);
}
//
...
It is popular in C, but not
part of the C standard
...

Note that using the integer 0 as the terminator would not have been portable: on some implementations, the integer 0 and the null pointer do not have the same representation (§6
...
8)
...


Section 12
...
4

Unspecified Number of Arguments

323

The error() function could be defined like this:
#include
void error(int severity
...
The macro va_start takes the name of
the va_list and the name of the last formal argument as arguments
...
In each call, the programmer must supply a type; va_arg()
assumes that an actual argument of that type has been passed, but it typically has no way of ensuring that
...
The reason is that va_start() may modify the stack in such a way that a return cannot successfully be done; va_end() undoes any such modifications
...
For example:
switch (argc) {
case 1:
error(0,{argv[0]});
break;
case 2:
error(0,{argv[0],argv[1]});
break;
default:
error(1,{argv[0],"with",to_string(argc−1),"arguments"});
}

324

Functions

Chapter 12

The int-to-string conversion function to_string() is provided by the standard library (§36
...
5)
...
push_back(argv[i]);
return res
}
int main(int argc, char∗ argv[])
{
auto args = arguments(argc,argv);
error((args
...

}

The helper function, arguments(), is trivial, and main() and error() are simple
...
That would allow later
improvements of error()
...


12
...
5 Default Arguments
A general function often needs more arguments than are necessary to handle simple cases
...
2
...
Consider class complex from §3
...
1
...

};

// construct complex from two scalars
// construct complex from one scalar

The actions of complex’s constructors are quite trivial, but logically there is something odd about
having three functions (here, constructors) doing essentially the same task
...
2
...
We could deal with the repetitiveness
by considering one of the constructors ‘‘the real one’’ and forward to that (§17
...
3):
complex(double r, double i) :re{r}, im{i} {}
complex(double r) :complex{2,0} {}
complex() :complex{0,0} {}

// construct complex from two scalars
// construct complex from one scalar
// default complex: {0,0}

Say we wanted to add some debugging, tracing, or statistics-gathering code to
have a single place to do so
...

The intent of having a single constructor plus some shorthand notation is now explicit
...
For example:
class X {
public:
static int def_arg;
void f(int =def_arg);
//
...
f();
// maybe f(7)
a
...
f();
// f(9)
}

Default arguments that can change value are most often best avoided because they introduce subtle
context dependencies
...
For example:
int f(int, int =0, char∗ =nullptr);// OK
int g(int =0, int =0, char∗);
// error
int h(int =0, int, char∗ =nullptr);
// error

Note that the space between the ∗ and the = is significant (∗= is an assignment operator; §10
...

For example:
void f(int x = 7);
void f(int = 7);
void f(int = 8);

// error: cannot repeat default argument
// error: different default arguments

326

Functions

Chapter 12

void g()
{
void f(int x = 9);
//
...


12
...
Using the same name for operations on different types is called overloading
...
That is, there is only one
name for addition, +, yet it can be used to add values of integer and floating-point types and combinations of such types
...
For
example:
void print(int);
// print an int
void print(const char∗); // print a C-style string

As far as the compiler is concerned, the only thing functions of the same name have in common is
that name
...
Thus, overloaded function names are primarily a notational convenience
...

When a name is semantically significant, this convenience becomes essential
...
2
...
1), and in
generic programming (§4
...

Templates provide a systematic way of defining sets of overloaded functions (§23
...


12
...
1 Automatic Overload Resolution
When a function fct is called, the compiler must determine which of the functions named fct to
invoke
...
The idea is to invoke the function that is the best match to
the arguments and give a compile-time error if no function is the best match
...
0);
print(1);
}

// print(long)
// print(double)
// error, ambiguous: print(long(1)) or print(double(1))?

Section 12
...
1

Automatic Overload Resolution

327

To approximate our notions of what is reasonable, a series of criteria are tried in order:
[1] Exact match; that is, match using no or only trivial conversions (for example, array name
to pointer, function name to pointer to function, and T to const T)
[2] Match using promotions; that is, integral promotions (bool to int, char to int, short to int,
and their unsigned counterparts; §10
...
1) and float to double
[3] Match using standard conversions (e
...
, int to double, double to int, double to long double,
Derived∗ to Base∗ (§20
...
2
...
5))
[4] Match using user-defined conversions (e
...
, double to complex; §18
...
in a function declaration (§12
...
4)
If two matches are found at the highest level where a match is found, the call is rejected as ambiguous
...
5)
...
The call print('a') invokes print(char) because 'a'
is a char (§6
...
3
...
The reason to distinguish between conversions and promotions is that we want
to prefer safe promotions, such as char to int, over unsafe conversions, such as int to char
...
3
...

Overload resolution is independent of the order of declaration of the functions considered
...
5
...
There are separate rules for overloading when a
{}-list is used (initializer lists take priority; §12
...
3, §17
...
4
...
5
...
1)
...
So, why bother? Consider the alternative to overloading
...
Without overloading, we
must define several functions with different names:

328

Functions

Chapter 12

void print_int(int);
void print_char(char);
void print_string(const char∗);

// C-style string

void g(int i, char c, const char∗ p, double d)
{
print_int(i);
// OK
print_char(c);
// OK
print_string(p);
// OK
print_int(c);
print_char(i);
print_string(i);
print_int(d);

// OK? calls print_int(int(c)), prints a number
// OK? calls print_char(char(i)), narrowing
// error
// OK? calls print_int(int(d)), narrowing

}

Compared to the overloaded print(), we have to remember several names and remember to use those
correctly
...
5), and generally
encourages the programmer to focus on relatively low-level type issues
...
It can also lead to errors
...
In particular, two calls rely on error-prone narrowing (§2
...
2, §10
...

Thus, overloading can increase the chances that an unsuitable argument will be rejected by the
compiler
...
3
...
The reason is to keep resolution for an individual operator (§18
...
1, §18
...
5) or function call context-independent
...


12
...
3 Overloading and Scope
Overloading takes place among the members of an overload set
...
For
example:

Section 12
...
3

Overloading and Scope

329

void f(int);
void g()
{
void f(double);
f(1);
// call f(double)
}

Clearly, f(int) would have been the best match for f(1), but only f(double) is in scope
...
As always, intentional
hiding can be a useful technique, but unintentional hiding is a source of surprises
...
For example:
struct Base {
void f(int);
};
struct Derived : Base {
void f(double);
};
void g(Derived& d)
{
d
...
3
...
4
...
2
...
Argument-dependent lookup (§14
...
4) can
also lead to overloading across namespaces
...
3
...
For example:
int pow(int, int);
double pow(double, double);
complex pow(double, complex);
complex pow(complex, int);
complex pow(complex, complex);
void k(complex z)
{
int i = pow(2,2);
double d = pow(2
...
0);
complex z2 = pow(2,z);
complex z3 = pow(z,2);
complex z4 = pow(z,z);
}

// invoke pow(int,int)
// invoke pow(double,double)
// invoke pow(double,complex)
// invoke pow(complex,int)
// invoke pow(complex,complex)

330

Functions

Chapter 12

In the process of choosing among overloaded functions with two or more arguments, a best match
is found for each argument using the rules from §12
...
A function that is the best match for one
argument and a better or equal match for all other arguments is called
...
For example:
void g()
{
double d = pow(2
...
0),2) or pow(2
...
0 is the best match for the first argument of pow(double,double) and
2 is the best match for the second argument of pow(int,int)
...
3
...
For
example:
void f1(char);
void f1(long);
void f2(char∗);
void f2(int∗);
void k(int i)
{
f1(i);
f2(0);
}

// ambiguous: f1(char) or f1(long)?
// ambiguous: f2(char*) or f2(int*)?

Where possible, consider the set of overloaded versions of a function as a whole and see if it makes
sense according to the semantics of the function
...
For example, adding
inline void f1(int n) { f1(long(n)); }

would resolve all ambiguities similar to f1(i) in favor of the larger type long int
...
For example:
f2(static_cast(0));

However, this is most often simply an ugly stopgap
...

Some C++ novices get irritated by the ambiguity errors reported by the compiler
...


12
...
Some of these expectations are expressed
in the argument types, but others depend on the actual values passed and on relationships among

Section 12
...
The compiler and linker can ensure that arguments are of the right types, but it is
up to the programmer to decide what to do about ‘‘bad’’ argument values
...
For example:
int area(int len, int wid)
/*
calculate the area of a rectangle

precondition: len and wid are positive
postcondition: the return value is positive
postcondition: the return value is the area of a rectange with sides len and wid
*/
{
return len∗wid;
}

Here, the statements of the pre- and postconditions are longer than the function body
...
For example, we learn that 0 and −12 are not considered valid arguments
...

What should we do about a call area(numeric_limits::max(),2)?
[1] Is it the caller’s task to avoid it? Yes, but what if the caller doesn’t?
[2] Is it the implementer’s task to avoid it? If so, how is an error to be handled?
There are several possible answers to these questions
...
It is also difficult for an implementer to cheaply, efficiently, and
completely check preconditions
...
For now, just note that some pre- and postconditions are
easy to check (e
...
, len is positive and len∗wid is positive)
...
For example, how do we test ‘‘the return value is the area of a rectangle with sides
len and wid’’? This is a semantic constraint because we have to know the meaning of ‘‘area of a
rectangle,’’ and just trying to multiply len and wid again with a precision that precluded overflow
could be costly
...
This is not uncommon
...
Mechanisms for documenting and enforcing conditions are discussed in §13
...

If a function depends only on its arguments, its preconditions are on its arguments only
...
g
...
In essence, we have to consider every nonlocal value
read as an implicit argument to a function
...


332

Functions

Chapter 12

The writer of a function has several alternatives, including:
[1] Make sure that every input has a valid result (so that we don’t have a precondition)
...

[3] Check that the precondition holds and throw an exception if it does not
...

If a postconditon fails, there was either an unchecked precondition or a programming error
...
4
discusses ways to represent alternative strategies for checking
...
5 Pointer to Function
Like a (data) object, the code generated for a function body is placed in memory somewhere, so it
has an address
...

However, for a variety of reasons – some related to machine architecture and others to system
design – a pointer to function does not allow the code to be modified
...
The pointer obtained by taking the address of
a function can then be used to call the function
...
*/ }
void (∗efct)(string);

// pointer to function taking a string argument and returning nothing

void f()
{
efct = &error;
efct("error");
}

// efct points to error
// call error through efct

The compiler will discover that efct is a pointer and call the function pointed to
...
Similarly, using & to get the address of a function
is optional:
void (∗f1)(string) = &error;
void (∗f2)(string) = error;
void g()
{
f1("Vasa");
(∗f1)("Mary Rose");
}

// OK: same as = error
// OK: same as = &error

// OK: same as (*f1)("Vasa")
// OK: as f1("Mary Rose")

Pointers to functions have argument types declared just like the functions themselves
...
For example:
void (∗pf)(string);
void f1(string);
int f2(string);
void f3(int∗);

// pointer to void(string)
// void(string)
// int(string)
// void(int*)

Section 12
...

You can convert a pointer to function to a different pointer-to-function type, but you must cast
the resulting pointer back to its original type or strange things may happen:
using P1 = int(∗)(int∗);
using P2 = void(∗)(void);
void f(P1 pf)
{
P2 pf2 = reinterpret_cast(pf)
pf2();
P1 pf1 = reinterpret_cast(pf2);
int x = 7;
int y = pf1(&x);
//
...
The
reason is that the result of using a pointer to function of the wrong type is so unpredictable and system-dependent
...
Because C does not have
function objects (§3
...
3) or lambda expressions (§11
...
For example, we can provide the comparison operation needed
by a sorting function as a pointer to function:
using CFT = int(const void∗, const void∗);
void ssort(void∗ base, size_t n, size_t sz, CFT cmp)
/*
Sor t the "n" elements of vector "base" into increasing order
using the comparison function pointed to by "cmp"
...


Shell sort (Knuth, Vol3, pg84)
*/

334

Functions

Chapter 12

{
for (int gap=n/2; 0for (int i=gap; i!=n; i++)
for (int j=i−gap; 0<=j; j−=gap) {
char∗ b = static_cast(base);
// necessar y cast
char∗ pj = b+j∗sz;
// &base[j]
char∗ pjg = b+(j+gap)∗sz;
// &base[j+gap]
if (cmp(pjg,pj)<0) {
// swap base[j] and base[j+gap]:
for (int k=0; k!=sz; k++) {
char temp = pj[k];
pj[k] = pjg[k];
pjg[k] = temp;
}
}
}
}

The ssort() routine does not know the type of the objects it sorts, only the number of elements (the
array size), the size of each element, and the function to call to perform a comparison
...
Real
programs use qsort(), the C++ standard-library algorithm sort (§32
...

This style of code is common in C, but it is not the most elegant way of expressing this algorithm in
C++ (see §23
...
3
...
1)
...
M
...
",
"Szymanski T
...
",
"Schryer N
...
",
"Schryer N
...
",
"Kernighan B
...
",
};

"dmr",
"ravi",
"tgs",
"nls",
"nls",
"bwk",

11271,
11272,
11273,
11274,
11275,
11276

void print_id(vector& v)
{
for (auto& x : v)
cout << x
...
id << '\t' << x
...
A comparison function
must return a negative value if its first argument is less than the second, zero if the arguments are
equal, and a positive number otherwise:

Section 12
...
This means that you cannot avoid the ugly and error-prone casts by writing:
int cmp3(const User∗ p, const User∗ q) // Compare ids
{
return strcmp(p−>id,q−>id);
}

The reason is that accepting cmp3 as an argument to ssort() would violate the guarantee that
will be called with arguments of type const User∗ (see also §15
...
6)
...
begin(), head
...
name ...
begin(), head
...
dept ...
If the explicit use of begin() and
annoying, it can be eliminated by using a version of sort() that takes a container (§14
...
5):

end()

is

sort(heads,[](const User& x, const User& y) { return x
...
name; });

You can take the address of an overloaded function by assigning to or initializing a pointer to function
...
For
example:
void f(int);
int f(char);
void (∗pf1)(int) = &f;
int (∗pf2)(char) = &f;
void (∗pf3)(char) = &f;

// void f(int)
// int f(char)
// error: no void f(char)

It is also possible to take the address of member functions (§20
...

A pointer to a noexcept function can be declared noexcept
...
2
...
Neither linkage specification
nor noexcept may appear in type aliases:
using Pc = extern "C" void(int);
using Pn = void(int) noexcept;

// error : linkage specification in alias
// error : noexcept in alias

12
...
The first rule about macros is:
don’t use them unless you have to
...
Because they rearrange the program text before
the compiler proper sees it, macros are also a major problem for many programming support tools
...
If you must use macros, please read the reference manual for your
own implementation of the C++ preprocessor carefully and try not to be too clever
...
The syntax of macros is
presented in §iso
...
3
...
6
...
3
...

A simple macro is defined like this:
#define NAME rest of line

Section 12
...
For example:
named = NAME

will expand into
named = rest of line

A macro can also be defined to take arguments
...
They will replace x and y when MAC()
is expanded
...
Only the expanded form of a macro is seen by the compiler, so an error in a
macro will be reported when the macro is expanded, not when it is defined
...

Here are some plausible macros:
#define CASE break;case
#define FOREVER for(;;)

Here are some completely unnecessary macros:
#define PI 3
...
3
...
For
example:
#define MIN(a,b) (((a)<(b))?(a):(b))

This handles the simpler syntax problems (which are often caught by compilers), but not the problems with side effects
...
For example:
#define M2(a) something(a)

/* thoughtful comment */

Using macros, you can design your own private language
...
Furthermore, the preprocessor is a very simple-minded macro processor
...
The auto, constexpr, const,
decltype, enum, inline, lambda expressions, namespace, and template mechanisms can be used as
better-behaved alternatives to many traditional uses of preprocessor constructs
...
A string can be created
by concatenating two strings using the ## macro operator
...
For example:
#define printx(x) cout << #x " = " << x << '\n';
int a = 7;
string str = "asdf";

Section 12
...
Adjacent string
literals are concatenated (§7
...
2)
...
This
affords some protection against undesired macros
...

The argument list (‘‘replacement list’’) of a macro can be empty:
#define EMPTY() std::cout<<"empty\n"
EMPTY();
// print "empty\n"
EMPTY;
// error: macro replacement list missing

I have a hard time thinking of uses of an empty macro argument list that are not error-prone or
malicious
...
For example:
#define err_print(
...
) means that
the output is:

__VA_ARGS__

represents the arguments actually passed as a string, so

error: The answer 54

12
...
1 Conditional Compilation
One use of macros is almost impossible to avoid
...
For example:
int f(int a
#ifdef arg_two
,int b
#endif
);

Unless a macro called arg_two has been #defined , this produces:
int f(int a
);

This example confuses tools that assume sane behavior from the programmer
...
See also §15
...
3
...
For example:

def

struct Call_info {
Node∗ arg_one;
Node∗ arg_two;
//
...


12
...
2 Predefined Macros
A few macros are predefined by the compiler (§iso
...
8, §iso
...
4
...
Its value is 201103L
in a C++11 program; previous C++ standards have lower values
...

• __TIME__: time in ‘‘hh:mm:ss’’ format
...

• __LINE__: source line number within the current source file
...

• __STDC_HOSTED__: 1 if the implementation is hosted (§6
...
1); otherwise 0
...
1) might have a code value that differs from its value as an ordinary character literal
• __STDCPP_STRICT_POINTER_SAFETY__: 1 if the implementation has strict pointer safety
(§34
...

• __STDCPP_THREADS__: 1 if a program can have more than one thread of execution; otherwise undefined
...
For example, NDEBUG is defined unless
the compilation is done in (some implementation-specific) ‘‘debug mode’’ and is used by the
assert() macro (§13
...
This can be useful, but it does imply that you can’t be sure of the meaning
of a program just by reading its source text
...
6
...
6
...

Obviously, the standard cannot specify how such facilities are provided, but one standard syntax is
a line of tokens prefixed with the preprocessor directive #pragma
...


12
...
1
...
1
...
1
...
1
...

If a function may have to be evaluated at compile time, declare it constexpr; §12
...
6
...
1
...

Use pass-by-value for small objects; §12
...
1
...
2
...

Return a result as a return value rather than modifying an object through an argument;
§12
...
1
...
2
...

Pass a pointer if ‘‘no object’’ is a valid alternative (and represent ‘‘no object’’ by nullptr);
§12
...
1
...
2
...

Use const extensively and consistently; §12
...
1
...
2
...

Avoid passing arrays as pointers; §12
...
2
...
2
...

Avoid unspecified numbers of arguments (
...
2
...

Use overloading when functions perform conceptually the same task on different types;
§12
...

When overloading on integers, provide functions to eliminate common ambiguities; §12
...
5
...
4
...
5
...
6
...
6
...

– Winston S
...
1 Error Handling
This chapter presents error handling using exceptions
...
Consequently, this chapter presents the exceptionsafety guarantees that are central to recovery from run-time errors and the Resource Acquisition Is
Initialization (RAII) technique for resource management using constructors and destructors
...

The language facilities and techniques presented here address problems related to the handling
of errors in software; the handling of asynchronous events is a different topic
...
Such parts of a program are often separately developed
...
’’ A library is just ordinary code, but in
the context of a discussion of error handling it is worth remembering that a library designer often
cannot even know what kind of programs the library will become part of:
• The author of a library can detect a run-time error but does not in general have any idea
what to do about it
...

The discussion of exceptions focuses on problems that need to be handled in long-running systems,
systems with stringent reliability requirements, and libraries
...
For example,
I would not apply every technique recommended here to a two-page program written just for
myself
...


13
...
1 Exceptions
The notion of an exception is provided to help get information from the point where an error is
detected to a point where it can be handled
...
A function that wants
to handle a kind of problem indicates that by catching the corresponding exception (§2
...
3
...

• A called component that cannot complete its assigned task reports its failure to do so by
throwing an exception using a throw-expression
...

if (/* could perform the task */)
return result;
else
throw Some_error{};
}

Section 13
...
1

Exceptions

345

The taskmaster() asks do_task() to do a job
...
Otherwise, do_task() must report a failure by throwing some exception
...
For example,
do_task() may call other functions to do a lot of subtasks, and one of those may throw because it
can’t do its assigned subtask
...

A called function cannot just return with an indication that an error happened
...
The exception-handling mechanism
is integrated with the constructor/destructor mechanisms and the concurrency mechanisms to help
ensure that (§5
...
The exception-handling mechanism:
• Is an alternative to the traditional techniques when they are insufficient, inelegant, or errorprone
• Is complete; it can be used to handle all errors detected by ordinary code
• Allows the programmer to explicitly separate error-handling code from ‘‘ordinary code,’’
thus making the program more readable and more amenable to tools
• Supports a more regular style of error handling, thus simplifying cooperation between separately written program fragments
An exception is an object thrown to represent the occurrence of an error
...
That way, we minimize the chances of two unrelated libraries using the same
value, say 17, to represent different errors, thereby throwing our recovery code into chaos
...
Thus, the simplest way of defining an exception is to define a class
specifically for a kind of error and throw that
...

}

If that gets tedious, the standard library defines a small hierarchy of exception classes (§13
...
2)
...
Its type represents the kind of
error, and whatever data it holds represents the particular occurrence of that error
...
5
...


13
...
2 Traditional Error Handling
Consider the alternatives to exceptions for a function detecting a problem that cannot be handled
locally (e
...
, an out-of-range access) so that an error must be reported to a caller
...
This is a pretty drastic approach
...
For example, in most situations we should at
least write out a decent error message or log the error before terminating
...
A library that unconditionally terminates cannot
be used in a program that cannot afford to crash
...
This is not always feasible because there is often no acceptable
‘‘error value
...
At a minimum, we would have to modify get_int() to return a pair
of values
...
This can easily double the size of a program (§13
...
7)
...

Consequently, this approach is rarely used systematically enough to detect all errors
...
3) returns a negative value if an output or encoding error occurred, but
programmers essentially never test for that
...

Return a legal value and leave the program in an ‘‘error state
...
For
example, many standard C library functions set the nonlocal variable errno to indicate an
error (§43
...
3):
double d = sqrt(−1
...
0 isn’t an acceptable
argument for a floating-point square root function
...
Furthermore, the use of nonlocal variables for
recording error conditions doesn’t work well in the presence of concurrency
...
For example:
if (something_wrong) something_handler(); // and possibly continue here

This must be some other approach in disguise because the problem immediately becomes
‘‘What does the error-handling function do?’’ Unless the error-handling function can completely resolve the problem, the error-handling function must in turn either terminate the
program, return with some indication that an error had occurred, set an error state, or throw
an exception
...


Section 13
...
3

Muddling Through

347

13
...
3 Muddling Through
One aspect of the exception-handling scheme that will appear novel to some programmers is that
the ultimate response to an unhandled error (an uncaught exception) is to terminate the program
...
Thus, exception handling makes programs more ‘‘brittle’’ in the sense that more care and effort must be taken to get a
program to run acceptably
...
Where termination is unacceptable, we can catch all exceptions (§13
...
2
...

Thus, an exception terminates a program only if a programmer allows it to terminate
...
Where termination is an acceptable response, an uncaught
exception will achieve that because it turns into a call of terminate() (§13
...
2
...
Also, a noexcept
specifier (§13
...
1
...

Sometimes, people try to alleviate the unattractive aspects of ‘‘muddling through’’ by writing
out error messages, putting up dialog boxes asking the user for help, etc
...
In the hands of nondevelopers, a library that asks the (possibly absent) user/operator for help is unacceptable
...
If a user has to be
informed, an exception handler can compose a suitable message (e
...
, in Finnish for Finnish users
or in XML for an error-logging system)
...
Only a part of the system that has some idea of the context in which the program runs has
any chance of composing a meaningful error message
...
The C++ exception-handling mechanism provides the programmer with a way of handling errors where they are most naturally handled, given the structure of a system
...
However, exceptions are not the cause of that complexity
...


13
...
4 Alternative Views of Exceptions
‘‘Exception’’ is one of those words that means different things to different people
...
In particular, it is intended to support error handling in programs composed of independently developed components
...
Can an event that happens most times a program is run be considered
exceptional? Can an event that is planned for and handled be considered an error? The answer to
both questions is ‘‘yes
...
’’

348

Exception Handling

Chapter 13

13
...
4
...
Asynchronous events, such as keyboard interrupts and power failures, are not necessarily exceptional and are not handled directly by this mechanism
...
Many systems offer mechanisms, such as signals, to deal with asynchrony, but because
these tend to be system-dependent, they are not described here
...
1
...
2 Exceptions That Are Not Errors
Think of an exception as meaning ‘‘some part of the system couldn’t do what it was asked to do’’
(§13
...
1, §13
...

Exception throws should be infrequent compared to function calls or the structure of the system
has been obscured
...

If an exception is expected and caught so that it has no bad effects on the behavior of the program, then how can it be an error? Only because the programmer thinks of it as an error and of the
exception-handling mechanisms as tools for handling errors
...
Consider a binary tree search function:
void fnd(Tree∗ p, const string& s)
{
if (s == p−>str) throw p;
if (p−>left) fnd(p−>left,s);
if (p−>right) fnd(p−>right,s);
}

// found s

Tree∗ find(Tree∗ p, const string& s)
{
try {
fnd(p,s);
}
catch (Tree∗ q) {
// q->str==s
return q;
}
return 0;
}

This actually has some charm, but it should be avoided because it is likely to cause confusion and
inefficiencies
...

When this is done, code is clearly separated into two categories: ordinary code and error-handling
code
...
Furthermore, the implementations of the exception
mechanisms are optimized based on the assumption that this simple model underlies the use of
exceptions
...
Anything that helps preserve a clear model of what is an
error and how it is handled should be treasured
...
1
...
1
...
However, we must reluctantly conclude that there are programs that for practical and historical reasons cannot use exceptions
...
In the absence of tools that can accurately estimate the maximum time for an exception to propagate from a throw to a catch, alternative
error-handling methods must be used
...
g
...
g
...
2, §4
...

In such cases, we are thrown back onto ‘‘traditional’’ (pre-exception) techniques
...
However, I can point to two popular techniques:
• To mimic RAII, give every class with a constructor an invalid() operation that returns some
error_code
...
If the constructor
fails to establish the class invariant, it ensures that no resource is leaked and invalid() returns
a nonzero error_code
...
A user can then systematically test invalid() after each construction of an object and
engage in suitable error handling in case of failure
...
invalid()) {
//
...

}
//
...
4
...
A user can then systematically test the error_code after
each function call and engage in suitable error handling in case of failure
...
second) {
//
...

}
auto val = v
...

}

Variations of this scheme have been reasonably successful, but they are clumsy compared to using
exceptions in a systematic manner
...
1
...
The assumption is that the two parts of the program are written independently and that the part of the program that handles the exception often can do something sensible about the error
...
That is, the various parts
of the program must agree on how exceptions are used and where errors are dealt with
...

This implies that the error-handling strategy is best considered in the earliest phases of a design
...
Something complicated would not be consistently adhered to in an area as inherently
tricky as error recovery
...
Each level copes with as many errors as it can
without getting too contorted and leaves the rest to higher levels
...

Furthermore, terminate() supports this view by providing an escape if the exception-handling mechanism itself is corrupted or if it has been incompletely used, thus leaving exceptions uncaught
...

Not every function should be a firewall
...
The reasons that this will not work vary from program to program and from programmer to programmer
...

[2] The overhead in time and space is too great for the system to run acceptably (there will be
a tendency to check for the same errors, such as invalid arguments, over and over again)
...

[4] This purely local notion of ‘‘reliability’’ leads to complexities that actually become a burden to overall system reliability
...
Thus, major libraries, subsystems, and
key interface functions should be designed in this way
...

Usually, we don’t have the luxury of designing all of the code of a system from scratch
...
To do this we must
address a variety of concerns relating to the way a program fragment manages resources and the
state in which it leaves the system after an error
...

Occasionally, it is necessary to convert from one style of error reporting to another
...
1
...
local cleanup, if possible and necessary
...
) {
//
...

errno = E_CPLPLFCTBLEWIT;
}
}

In such cases, it is important to be systematic enough to ensure that the conversion of error-reporting styles is complete
...

Error handling should be – as far as possible – hierarchical
...
Such requests set
up cycles in the system dependencies
...


13
...
7 Exceptions and Efficiency
In principle, exception handling can be implemented so that there is no run-time overhead when no
exception is thrown
...
Doing so without adding significant memory overhead while
maintaining compatibility with C calling sequences, debugger conventions, etc
...
However, please remember that the alternatives to exceptions are not free either
...

Consider a simple function f() that appears to have nothing to do with exception handling:
void f()
{
string buf;
cin>>buf;
//
...

Had g() not thrown an exception, it would have had to report its error some other way
...

if (g(1)) {
if (h(s)) {
free(s);
return true;
}
else {
free(s);
return false;
}
}
else {
free(s);
return false;
}
}

Using a local buffer for s would simplify the code by eliminating the calls to free(), but then we’d
have range-checking code instead
...

People don’t usually handle errors this systematically, though, and it is not always critical to do
so
...

The noexcept specifier (§13
...
1
...
Consider:
void g(int) noexcept;
void h(const string&) noexcept;

Now, the code generated for f() can possibly be improved
...

In particular, a standard-library implementer knows that only a few standard C library functions
(such as atexit() and qsort()) can throw, and can take advantage of that fact to generate better code
...
For example, it might have been converted to use the C++ operator new, which can
throw bad_alloc, or it might call a C++ library that throws an exception
...


Section 13
...
2 Exception Guarantees
To recover from an error – that is, to catch an exception and continue executing a program – we
need to know what can be assumed about the state of the program before and after the attempted
recovery action
...
Therefore, we call an operation exceptionsafe if that operation leaves the program in a valid state when the operation is terminated by throwing an exception
...
’’ For practical design using exceptions, we must also break down the
overly general ‘‘exception-safe’’ notion into a few specific guarantees
...
4
...
2, §17
...
1)
...
So, by valid state we mean that a
constructor has completed and the destructor has not yet been entered
...
That is, if two pieces of nonlocal data are assumed
to have a specific relationship, we must consider that an invariant and our recovery action must preserve it
...
size()==vy
...
However, that was only stated in a comment, and compilers do not read comments
...

Before a throw, a function must place all constructed objects in valid states
...
For example, a string may be left as the empty
string or a container may be left unsorted
...

The C++ standard library provides a generally useful conceptual framework for design for
exception-safe program components
...
In particular, the basic invariants of every
built-in and standard-library type guarantee that you can destroy an object or assign to it
after every standard-library operation (§iso
...
6
...
1)
...
This guarantee is provided for key operations,
such as push_back(), single-element insert() on a list, and uninitialized_copy()
...
This guarantee is provided for a
few simple operations, such as swap() of two containers and pop_back()
...
17
...
5
...

Violating a standard-library requirement, such as having a destructor exit by throwing an exception,
is logically equivalent to violating a fundamental language rule, such as dereferencing a null
pointer
...

Both the basic guarantee and the strong guarantee require the absence of resource leaks
...
In particular, an operation that throws
an exception must not only leave its operands in well-defined states but must also ensure that every
resource that it acquired is (eventually) released
...
For example:
void f(int i)
{
int∗ p = new int[10];
//
...

}

Remember that memory isn’t the only kind of resource that can leak
...
Files, locks, network connections, and threads are examples of system resources
...

The C++ language rules for partial construction and destruction ensure that exceptions thrown
while constructing subobjects and members will be handled correctly without special attention
from standard-library code (§17
...
3)
...

In general, we must assume that every function that can throw an exception will throw one
...
When analyzing code for potential errors, simple,
highly structured, ‘‘stylized’’ code is the ideal; §13
...


13
...
– it is often essential for the future running of the system that the
resource be properly released
...
For example:

Section 13
...
use f
...
Exactly the same problem can occur in languages that do not support exception handling
...
Even an ordinary return-statement could exit use_file without closing f
...
use f
...
) {
// catch every possible exception
fclose(f);
throw;
}
fclose(f);
}

The code using the file is enclosed in a try-block that catches every exception, closes the file, and
rethrows the exception
...
Worse
still, such code becomes significantly more complex when several resources must be acquired and
released
...
The general form of the problem looks like
this:
void acquire()
{
// acquire resource 1
//
...
use resources
...

// release resource 1
}

It is typically important that resources are released in the reverse order of their acquisition
...
Thus, we can handle such resource acquisition and release problems using objects of classes
with constructors and destructors
...
c_str(),a}
{}
explicit File_ptr(FILE∗ pp)
// assume ownership of pp
:p{pp}
{
if (p==nullptr) throw runtime_error("File_ptr: nullptr"};
}
//
...

˜File_ptr() { fclose(p); }
operator FILE∗() { return p; }
};

We can construct a File_ptr given either a FILE∗ or the arguments required for fopen()
...
File_ptr
throws an exception if it cannot open a file because otherwise every operation on the file handle
would have to test for nullptr
...
use f
...
That is, the exception-handling mechanisms enable us to remove
the error-handling code from the main algorithm
...

This technique for managing resources using local objects is usually referred to as ‘‘Resource
Acquisition Is Initialization’’ (RAII; §5
...
This is a general technique that relies on the properties
of constructors and destructors and their interaction with exception handling
...
3

Resource Management

357

It is often suggested that writing a ‘‘handle class’’ (a RAII class) is tedious so that providing a
nicer syntax for the catch(
...
The problem with that
approach is that you need to remember to ‘‘catch and correct’’ the problem wherever a resource is
acquired in an undisciplined way (typically dozens or hundreds of places in a large program),
whereas the handler class need be written only once
...
Then and only then
will stack unwinding (§13
...
1) call the destructor for the object
...
An array is constructed to the
extent that its elements have been constructed (and only fully constructed elements are destroyed
during unwinding)
...
When that
cannot be achieved, a well-written constructor restores – as far as possible – the state of the system
to what it was before creation
...
This can be simply
achieved by applying the RAII technique to the members
...
3
...
This acquisition might fail and throw an exception
...
Furthermore, this should be achieved without imposing a burden of complexity on the programmer
...
3
...
The acquisition of a resource is represented by the initialization of the local object that
represents the resource:
class Locked_file_handle {
File_ptr p;
unique_lock lck;
public:
X(const char∗ file, mutex& m)
: p{file,"rw"},
// acquire ‘‘file’’
lck{m}
// acquire ‘‘m’’
{}
//
...
The user
doesn’t have to keep track at all
...

This implies that where this simple model for acquisition of resources is adhered to, the author
of the constructor need not write explicit exception-handling code
...
Compared to ad hoc memory management
using new (and possibly also delete), this saves lots of work and avoids lots of errors
...
2
...
3) to avoid leaks
...
3
...
Again and again, people have invented ‘‘finally’’ language constructs for writing arbitrary code to clean up after an exception
...
First, we define a class
that will execute an arbitrary action from its destructor
...

Next, we define a function that conveniently deduces the type of an action:
template
Final_action finally(F f)
{
return Final_action(f);
}

Finally, we can test finally():
void test()
// handle undiciplined resource acquisition
// demonstrate that arbitrary actions are possible
{
int∗ p = new int{7};
// probably should use a unique_ptr (§5
...
3
...

It is generally a good idea to place a guard close to the definition of whatever it is guarding
...
The connection between finally() actions and the resources they manipulate is still ad hoc and implicit compared to the use of RAII for resource handles, but using finally()
is far better than scattering cleanup code around in a block
...
5
...
It says what is to be done upon exit
from a scope, saving the programmer from trying to write code at each of the potentially many
places from which the thread of control might exit the scope
...
4 Enforcing Invariants
When a precondition for a function (§12
...

Similarly, when a constructor cannot establish its class invariant (§2
...
3
...
2
...
In those cases, I typically throw exceptions
...
1
...

• Terminate the program: Violating a precondition is a serious design error, and the program
must not proceed in the presence of such errors
...

Why would anyone choose one of these alternatives? The first approach often relates to the need
for performance: systematically checking preconditions can lead to repeated tests of logically
unnecessary conditions (for example, if a caller has correctly validated data, millions of tests in
thousands of called functions may be logically redundant)
...
It may be worthwhile to suffer repeated crashes during testing to gain that performance
...
For some systems, typically systems completely under the control of a single organization,
that can be a realistic aim
...
That is, making sure that recovery is complete
imposes unacceptable complexity on the system design and implementation
...
For example, it is not unreasonable to consider
program termination acceptable if it is easy to rerun the program with inputs and parameters that
make repeated failure unlikely
...

Realistically, many systems use a mix of exceptions and these two alternative approaches
...
Program structure can be radically different depending on whether (localized) recovery is an aim
...
For example, I often throw an exception to
ensure some error logging or to produce a decent error message before terminating or re-initializing
a process (e
...
, from a catch(
...

A variety of techniques are used to express checks of desired conditions and invariants
...
An assertion is simply a logical expression that is assumed to be
true
...
Looking at a variety of systems, I see a variety of needs when it comes to
expressing assertions:
• We need to choose between compile-time asserts (evaluated by the compiler) and run-time
asserts (evaluated at run time)
...

• No code should be generated unless some logical condition is true
...
Usually, the logical
condition is something like a debug flag, a level of checking, or a mask to select among
asserts to enforce
...

Not every system has a need for or supports every alternative
...
6
...
If
the assertion fails, the compiler writes out an error message containing the (failed) assertion,
the source file name, and the source file line number and terminates the program
...
4
...
3)
...

Where assert() and static_assert() are insufficient, we could use ordinary code for checking
...

}

Section 13
...
Are we:
• Evaluating the conditions under which we test? (Yes, the 2 ...
1
...
2
...
)
Worse, the precondition testing (or invariant testing) can easily get dispersed in other code and thus
be harder to spot and easier to get wrong
...
What follows here is a (possibly slightly overelaborate) mechanism for
expressing a variety of assertions and a variety of responses to failures
...

}

The idea is to test whenever an assertion has a ‘‘level’’ lower than or equal to current_level
...
The current_level and current_mode are constants because the idea is to generate no code whatsoever for an assertion unless
we have made a decision to do so
...

The programmer will use Assert::dynamic() to make assertions:
namespace Assert {
//
...
str();
}

362

Exception Handling

Chapter 13

template
void dynamic(bool assertion, const string& message ="Assert::dynamic failed")
{
if (assertion)
return;
if (current_mode == Assert_mode::throw_)
throw Except{message};
if (current_mode == Assert_mode::terminate_)
std::terminate();
}
template<>
void dynamic(bool, const string&)
{
}

// do nothing

void dynamic(bool b, const string& s)
{
dynamic(b,s);
}

// default action

void dynamic(bool b)
{
dynamic(b);
}

// default message

}

I chose the name Assert::dynamic (meaning ‘‘evaluate at run time’’) to contrast with static_assert
(meaning ‘‘evaluate at compile time’’; §2
...
3
...

Further implementation trickery could be used to minimize the amount of code generated
...
This Assert
is not part of the standard and is presented primarily as an illustration of the problems and the
implementation techniques
...

We can use Assert::dynamic like this:
void f(int n)
// n should be in [1:max)
{
Assert::dynamic(
(n<=0 || max//
...
6
...
I can’t hide them from the user’s view by placing them inside the implementation of
Assert where they belong
...
Similarly, if we are
willing to use the default assertion level, we don’t need to mention the level explicitly:

Section 13
...

}

I do not recommend obsessing about the amount of text needed to express an assertion, but by
using a namespace directive (§14
...
3) and the default message, we can get to a minimum:
void f(int n)
// n should be in [1:max)
{
dynamic(n<=0||max//
...
g
...
That way, you can
have a debug version of a system that tests extensively and enters the debugger and a production
version that does hardly any testing
...
For
example, with Assert the obvious convention is that assertions marked as level zero will always be
checked
...
Also, even if all else works perfectly, having a few ‘‘sanity checks’’ left to deal with hardware failures can be wise
...

The writer of a library or reusable component usually does not have the luxury of terminating
unconditionally
...

As usual, destructors should not throw, so don’t use a throwing Assert() in a destructor
...
5 Throwing and Catching Exceptions
This section presents exceptions from a language-technical point of view
...
5
...
For example:
class No_copy {
No_copy(const No_copy&) = delete;
};
class My_error {
//
...
6
...
5
...
This temporary may be further copied several times before it is caught: the exception is passed
(back) from called function to calling function until a suitable handler is found
...
The data in the exception object – if any – is typically used to produce error messages or to help recovery
...
In each scope exited, the destructors are invoked so that every fully constructed object is properly destroyed
...

}
}
void g()
{
string s = "excess";
{
string s = "or";
h();
}
}
void h()
{
string s = "not";
throw My_error{};
string s2 = "at all";
}

After the throw in h(), all the strings that were constructed are destroyed in the reverse order of their
construction: "not", "or", "excess", "in", but not "at all", which the thread of control never reached,
and not "Byron", which was unaffected
...
5
...
Exceptions containing a few words are very common
...
g
...
Some of the most common exceptions carry no information; the name of the type is sufficient to report the error
...

if (something_wrong)
throw Some_error{};
}

There is a small standard-library hierarchy of exception types (§13
...
2) that can be used either
directly or as base classes
...

For example:
void g(int n)
// throw some exception
{
if (n)
throw std::runtime_error{"I give up!"};
else
throw My_error2{};
}
void f(int n)
// see what exception g() throws
{
try {
void g(n);
}
catch (std::exception& e) {
cerr << e
...
5
...
1 noexcept Functions
Some functions don’t throw exceptions and some really shouldn’t
...
For example:
double compute(double) noexcept; // may not throw an exception

366

Exception Handling

Chapter 13

Now no exception will come out of compute()
...
The programmer need not worry about providing
try-clauses (for dealing with failures in a noexcept function) and an optimizer need not worry about
control paths from exception handling
...
What happens if the
programmer ‘‘lied’’ so that a noexcept function deliberately or accidentally threw an exception that
wasn’t caught before leaving the noexcept function? Consider:
double compute(double x) noexcept;
{
string s = "Courtney and Anya";
vector tmp(10);
//
...
In
that case, the program terminates
...
4
...
3)
...
It is implementation-defined
whether destructors from scopes between the throw and the noexcept (e
...
, for s in compute()) are
invoked
...

By adding a noexcept specifier, we indicate that our code was not written to cope with a throw
...
5
...
2 The noexcept Operator
It is possible to declare a function to be conditionally noexcept
...
I may want to write this if my_fct() copies its argument
...
g
...

The predicate in a noexcept() specification must be a constant expression
...

The standard library provides many type predicates that can be useful for expressing the conditions under which a function may throw an exception (§35
...

What if the predicate we want to use isn’t easily expressed using type predicates only? For
example, what if the critical operation that may or may not throw is a function call f(x)? The noexcept() operator takes an expression as its argument and returns true if the compiler ‘‘knows’’ that it
cannot throw and false otherwise
...
5
...
2

The noexcept Operator

367

The double mention of noexcept looks a bit odd, but noexcept is not a common operator
...

A noexcept(expr) operator does not go to heroic lengths to determine whether expr can throw; it
simply looks at every operation in expr and if they all have noexcept specifications that evaluate to
true, it returns true
...

Conditional noexcept specifications and the noexcept() operator are common and important in
standard-library operations that apply to containers
...
20
...
2):
template
void swap(T (&a)[N], T (&b)[N]) noexcept(noexcept(swap(∗a, ∗b)));

13
...
1
...
For example:
void f(int) throw(Bad,Worse); // may only throw Bad or Worse exceptions
void g(int) throw();
// may not throw

An empty exception specification throw() is defined to be equivalent to noexcept (§13
...
1
...
That
is, if an exception is thrown, the program terminates
...
The default effect of an unexpected
exception is to terminate the program (§30
...
1
...
A nonempty throw specification is hard to use
well and implies potentially expensive run-time checks to determine if the right exception is
thrown
...
Don’t use it
...


13
...
2 Catching Exceptions
Consider:
void f()
{
try {
throw E{};
}
catch(H) {
// when do we get here?
}
}

The handler is invoked:
[1] If H is the same type as E
[2] If H is an unambiguous public base of E
[3] If H and E are pointer types and [1] or [2] holds for the types to which they refer
[4] If H is a reference and [1] or [2] holds for the type to which H refers
In addition, we can add const to the type used to catch an exception in the same way that we can

368

Exception Handling

Chapter 13

add it to a function parameter
...

In principle, an exception is copied when it is thrown (§13
...
The implementation may apply a
wide variety of strategies for storing and transmitting exceptions
...
2
...

Note the possibility of catching an exception by reference
...
For examples, see §13
...
2
...
4
...
1
...

The {} in both the try-part and a catch-clause of a try-block are real scopes
...
For example:
void g()
{
int x1;
try {
int x2 = x1;
//
...

}
catch(
...

}
++x1;
++x2;
++x3;

// OK
// error: x2 not in scope
// error: x3 not in scope

}

The ‘‘catch everything’’ clause, catch(
...
5
...
2
...
5
...
1 Rethrow
Having caught an exception, it is common for a handler to decide that it can’t completely handle
the error
...
Thus, an error can be handled where it is most appropriate
...
For example:

Section 13
...
2
...
code that might throw an exception
...
handle it
...
do what can be done here
...
A rethrow may occur in a catch-clause or in
a function called from a catch-clause
...
5
...
5) will be called
...

The exception rethrown is the original exception caught and not just the part of it that was
accessible as an exception
...
Had I written throw err; instead
of the simpler throw;, the exception would have been sliced (§17
...
1
...


13
...
2
...
4
...
1)
...
do something
...
cleanup
...
However, the standard-library exceptions are just
one set of exception types
...
If someone (unwisely) threw an int or an exception from some application-specific hierarchy,
it would not be caught by the handler for std::exception&
...
For example, if m() is supposed
to leave some pointers in the state in which it found them, then we can write code in the handler to

370

Exception Handling

Chapter 13

give them acceptable values
...
, indicates ‘‘any argument’’ (§12
...
4),
so catch(
...
’’ For example:
void m()
{
try {
//
...

}
catch (
...
cleanup
...
5
...
3 Multiple Handlers
A try-block may have multiple catch-clauses (handlers)
...
The handlers are tried in order
...

}
catch (std::ios_base::failure) {
//
...
4
...
1)
...
handle any standard-librar y exception (§30
...
1
...

}
catch (
...
handle any other exception (§13
...
2
...

}
}

The compiler knows the class hierarchy, so it can warn about many logical mistakes
...

}
catch (
...
handle every exception (§13
...
2
...

}
catch (std::exception& e) {
//
...
4
...
1)
...
5
...
3

Multiple Handlers

371

catch (std::bad_cast) {
//
...
2
...

}
}

Here, the exception is never considered
...
Matching exception types to catchclauses is a (fast) run-time operation and is not as general as (compile-time) overload resolution
...
5
...
4 Function try-Blocks
The body of a function can be a try-block
...
do something
...
} {
//
...

}

For most functions, all we gain from using a function try-block is a bit of notational convenience
...
4)
...
However, the
constructor itself can catch such exceptions by enclosing the complete function body – including
the member initializer list – in a try-block
...

public:
X(int,int);
//
...

}
catch (std::exception& err) { // exceptions thrown for vi and vs are caught here
//
...
Similarly, we can catch exceptions
thrown by member destructors in a destructor (though a destructor should never throw)
...
Also, other
member objects will either not be constructed or already have had their destructors invoked as part
of the stack unwinding
...
The default action is to rethrow the original exception when we ‘‘fall off the
end’’ of the catch-clause (§iso
...
3)
...


13
...
2
...
The guiding principles are:
• Don’t throw an exception while handling an exception
...

If the exception-handling implementation catches you doing either, it will terminate your program
...
Note that an exception is considered handled immediately upon entry
into a catch-clause
...
5
...
1) or throwing a new exception from within
a catch-clause is considered a new throw done after the original exception has been handled
...

The specific rules for calling terminate() are (§iso
...
5
...
g
...
In addition, a user can call terminate() if less
drastic approaches are infeasible
...

By default, terminate() will call abort() (§15
...
3)
...
If that is not acceptable, the user can provide a terminate
handler function by a call std::set_terminate() from :

Section 13
...
2
...

set_terminate(old); // restore the old terminate handler
}

The return value is the previous function given to set_terminate()
...
The intent is for terminate() to be a drastic measure to be applied when the error recovery
strategy implemented by the exception-handling mechanism has failed and it is time to go to
another level of a fault tolerance strategy
...
Even writing
an error message using cerr must be assumed to be hazardous
...
A throw or even a return before set_terminate(old) will leave
my_handler in place when it wasn’t meant to be
...
3)
...
If it tries to, terminate() will call abort()
...
The function exit() can be used to
exit a program with a return value that indicates to the surrounding system whether the exit is normal or abnormal (§15
...
3)
...
On some systems, it is essential that the destructors are not
called so that the program can be resumed from the debugger
...

If you want to ensure cleanup when an otherwise uncaught exception happens, you can add a
catch-all handler (§13
...
2
...

For example:
int main()
try {
//
...
handle my error
...
) {
//
...
5
...
There is no way of catching exceptions thrown during initialization or destruction of namespace and thread-local variables
...

When an exception is caught, the exact point where it was thrown is generally not known
...
In some C++ development environments, for some programs, and for some people, it might
therefore be preferable not to catch exceptions from which the program isn’t designed to recover
...
4) for an example of how one might encode the location of a throw into the
thrown exception
...
5
...
3
...
2), std::terminate() (§13
...
2
...
So, if
we don’t want an error in a thread to stop the whole program, we must catch all errors from which
we would like to recover and somehow report them to a part of the program that is interested in the
results of the thread
...
) (§13
...
2
...

We can transfer an exception thrown on one thread to a handler on another thread using the
standard-library function current_exception() (§30
...
1
...
For example:
try {
//
...

}
catch(
...
set_exception(current_exception());
}

This is the basic technique used by packaged_task to handle exceptions from user code (§5
...
5
...


13
...

Obviously, a vector implementation relies on many language facilities provided to support the
implementation and use of classes
...
However, a good understanding of the use of exceptions in C++ requires a more
extensive example than the code fragments so far in this chapter
...
6

A vector Implementation

375

The basic tools available for writing exception-safe code are:
• The try-block (§13
...

• The support for the ‘‘Resource Acquisition Is Initialization’’ technique (§13
...

The general principles to follow are to
• Never let go of a piece of information before its replacement is ready for use
...

That way, we can always back out of an error situation
...

Knowing what to look for in an application takes experience
...
2) and always to provide the basic guarantee
...
For example, if I write a simple data analysis program for my
own use, I’m usually quite willing to have the program terminate in the unlikely event of memory
exhaustion
...
In particular, the techniques for providing basic exception safety, such as defining and checking invariants (§13
...
It follows that the overhead of providing the basic exception-safety guarantee (§13
...


13
...
1 A Simple vector
A typical implementation of vector (§4
...
1, §31
...
2
...
The default allocator (§34
...
1) uses new and delete to acquire and release memory
...

};

Consider first a naive implementation of the constructor that initializes a
tialized to val:

vector

to

n

elements ini-

template
vector::vector(size_type n, const T& val, const A& a) // warning: naive implementation
:alloc{a}
// copy the allocator
{
elem = alloc
...
4)
space = last = elem+n;
for (T∗ p = elem; p!=last; ++p)
a
...
4)
}

There are two potential sources of exceptions here:
[1] allocate() may throw an exception if no memory is available
...

What about the copy of the allocator? We can imagine that it throws, but the standard specifically
requires that it does not do that (§iso
...
6
...
5)
...

In both cases of a throw, no vector object is created, so vector’s destructor is not called (§13
...

When allocate() fails, the throw will exit before any resources are acquired, so all is well
...
Worse still, the copy constructor for T might throw an exception after correctly constructing a few elements but before constructing them all
...


Section 13
...
1

A Simple vector

377

To handle this problem, we could keep track of which elements have been constructed and
destroy those (and only those) in case of an error:
template
vector::vector(size_type n, const T& val, const A& a)
// elaborate implementation
:alloc{a}
// copy the allocator
{
elem = alloc
...
construct(p,val);
last = space = p;
}
catch (
...
destroy(q);
alloc
...
4)

// destroy constructed elements
// free memory
// rethrow

}

Note that the declaration of p is outside the try-block; otherwise, we would not be able to access it
in both the try-part and the catch-clause
...
In a good C++ implementation, this overhead is negligible compared to the cost of allocating memory and initializing elements
...

The main part of this constructor is a repeat of the implementation of std::uninitialized_fill():
template
void uninitialized_fill(For beg, For end, const T& x)
{
For p;
try {
for (p=beg; p!=end; ++p)
::new(static_cast(&∗p)) T(x);
}
catch (
...
2
...
2
...
5
...
1)

The curious construct &∗p takes care of iterators that are not pointers
...
Together with the explicitly

378

Exception Handling

Chapter 13

global ::new, the explicit cast to void∗ ensures that the standard-library placement function (§17
...
4)
is used to invoke the constructor, and not some user-defined operator new() for T∗s
...
construct() in the vector constructors are simply syntactic sugar for this placement new
...
destroy() call simply hides explicit destruction (like (&∗q)−>˜T())
...

Fortunately, we don’t have to invent or implement uninitialized_fill(), because the standard library
provides it (§32
...
6)
...
Consequently, the standard library provides uninitialized_fill(), uninitialized_fill_n(), and uninitialized_copy()
(§32
...
6), which offer the strong guarantee (§13
...

The uninitialized_fill() algorithm does not protect against exceptions thrown by element destructors or iterator operations (§32
...
6)
...

The uninitialized_fill() algorithm can be applied to many kinds of sequences
...
1
...

Using uninitialized_fill(), we can simplify our constructor:
template
vector::vector(size_type n, const T& val, const A& a)
// still a bit messy
:alloc(a)
// copy the allocator
{
elem = alloc
...
) {
alloc
...

The constructor rethrows a caught exception
...
All standard-library containers
have this property
...
This is in contrast to major parts of a system (‘‘modules’’) that generally need
to take responsibility for all exceptions thrown
...
Achieving this may involve grouping exceptions into hierarchies (§13
...
2) and using catch(
...
5
...
2)
...
6
...
In fact, it is unnecessarily difficult because there is an alternative: The

Section 13
...
2

Representing Memory Explicitly

379

‘‘Resource Acquisition Is Initialization’’ technique (§13
...
In this case, the key resource
required by the vector is memory to hold its elements
...
allocate(n)}, space{elem+n}, last{elem+n} { }
˜vector_base() { alloc
...
Class vector_base deals with
memory for a type T, not objects of type T
...

The vector_base is designed exclusively to be part of the implementation of vector
...
alloc},
elem{a
...
space},
last{a
...
elem = a
...
last = nullptr; // no longer owns any memor y
}
template
vector_base::& vector_base::operator=(vector_base&& a)
{
swap(∗this,a);
return ∗this;
}

380

Exception Handling

Chapter 13

This definition of the move assignment uses swap() to transfer ownership of any memory allocated
for elements
...

Given vector_base, vector can be defined like this:
template >
class vector {
vector_base vb;
void destroy_elements();
public:
using size_type = unsigned int;

// the data is here

explicit vector(size_type n, const T& val = T(), const A& = A());
vector(const vector& a);
vector& operator=(const vector& a);

// copy constructor
// copy assignment

vector(vector&& a);
vector& operator=(vector&& a);

// move constructor
// move assignment

˜vector() { destroy_elements(); }
size_type size() const { return vb
...
elem; }
size_type capacity() const { return vb
...
elem; }
void reserve(size_type);

// increase capacity

void resize(size_type, T = {});
void clear() { resize(0); }
void push_back(const T&);

// change the number of elements
// make the vector empty
// add an element at the end

//
...
elem; p!=vb
...
2
...
space=vb
...
This implies that if an
element destructor throws an exception, the vector destruction fails
...
5
...
5)
...
There is no
really good way to protect against exceptions thrown from destructors, so the library makes no
guarantees if an element destructor throws (§13
...


Section 13
...
2

Representing Memory Explicitly

381

Now the constructor can be simply defined:
template
vector::vector(size_type n, const T& val, const A& a)
:vb{a,n}
// allocate space for n elements
{
uninitialized_fill(vb
...
elem+n,val); // make n copies of val
}

The simplification achieved for this constructor carries over to every vector operation that deals
with initialization or allocation
...
alloc,a
...
begin(),a
...
elem);
}

This style of constructor relies on the fundamental language rule that when an exception is thrown
from a constructor, subobjects (including bases) that have already been completely constructed will
be properly destroyed (§13
...
The uninitialized_fill() algorithm and its cousins (§13
...
1) provide the
equivalent guarantee for partially constructed sequences
...
vb)}
// transfer ownership
{
}

// move constructor

The vector_base move constructor will set the argument’s representation to ‘‘empty
...
However, I don’t know if some programmer has been
playing games with std::move()
...
6
...
First
consider a straightforward implementation:

382

Exception Handling

Chapter 13

template
vector& vector::operator=(const vector& a)
// offers the strong guarantee (§13
...
size());
// get memory
uninitialized_copy(a
...
end(),b
...
We can avoid repetition:
template
vector& vector::operator=(const vector& a)
{
vector temp {a};
// copy allocator
std::swap(∗this,temp);
// swap representations
return ∗this;
}

// offers the strong guarantee (§13
...

The reason that the standard-library swap() (§35
...
2) works for vector_bases is that we defined
vector_base move operations for swap() to use
...
Essentially, they are just two different ways of specifying the same set of operations
...

Note that I did not test for self-assignment, such as v=v
...
This obviously handles self-assignment correctly
...

In either case, two potentially significant optimizations are missing:
[1] If the capacity of the vector assigned to is large enough to hold the assigned vector, we
don’t need to allocate new memory
...

Implementing these optimizations, we get:
template
vector& vector::operator=(const vector& a)
// optimized, basic guarantee (§13
...
size()) { // allocate new vector representation:
vector temp {a};
// copy allocator
swap(∗this,temp);
// swap representations
return ∗this;
// implicitly destroy the old value
}

Section 13
...
3

Assignment

if (this == &a) return ∗this;

383

// optimize self assignment

size_type sz = size();
size_type asz = a
...
alloc = a
...
alloc;
// copy the allocator
if (asz<=sz) {
copy(a
...
begin()+asz,vb
...
elem+asz; p!=vb
...
2
...
begin(),a
...
elem);
uninitialized_copy(a
...
end(),vb
...
space = vb
...
Obviously, the complexity of the code is far higher
...
However, I do so mostly to show how it is done because here it is only an
optimization
...
5
...
Thus, if
T::operator=() throws an exception during copy(), the vector being assigned to need not be a copy of
the vector being assigned, and it need not be unchanged
...
It is also plausible that an element – the element that was being copied when T::operator=() threw an exception – ends up with a
value that is neither the old value nor a copy of the corresponding element in the vector being
assigned
...

The standard-library vector assignment offers the (weaker) basic exception-safety guarantee of
this last implementation – and its potential performance advantages
...
For example:
template
void safe_assign(vector& a, const vector& b)
// simple a = b
{
vector temp{b};
// copy the elements of b into a temporar y
swap(a,temp);
}

Alternatively, we could simply use call-by-value (§12
...


384

Exception Handling

Chapter 13

13
...
4 Changing Size
One of the most useful aspects of vector is that we can change its size to suit our needs
...
push_back(x), which adds an x at the end of v, and
v
...


13
...
4
...
In other words, reserve() increases the capacity() of a vector
...
We could try the trick from the unoptimized assignment (§13
...
3):
template
void vector::reserve(size_type newalloc)
// flawed first attempt
{
if (newalloc<=capacity()) return;
// never decrease allocation
vector v(capacity());
// make a vector with the new capacity
copy(elem,elem+size(),v
...
However, not all types have a default
value, so this implementation is flawed
...
So let us optimize:
template
void vector::reserve(size_type newalloc)
{
if (newalloc<=capacity()) return;
vector_base b {vb
...
elem);
swap(vb,b);
} // implicitly release old space

// never decrease allocation
// get new space
// move elements
// install new base

The problem is that the standard library doesn’t offer uninitialized_move(), so we have to write it:
template
Out uninitialized_move(In b, In e, Out oo)
{
for (; b!=e; ++b,++oo) {
new(static_cast(&∗oo)) T{move(∗b)}; // move construct
b−>˜T();
// destroy
}
return b;
}

In general, there is no way of recovering the original state from a failed move, so I don’t try to
...
However, it is simple and for the vast
majority of cases it is fast
...


Section 13
...
4
...
3
...

Remember that a move operation should not throw
...
A throw from a
move operation is rare, unexpected, and damaging to normal reasoning about code
...
The standard-library move_if_noexcept() operations may be of help here (§35
...
1)
...


13
...
4
...
Given reserve(), the implementation resize() is fairly simple
...
Conversely, if the number of elements decrease, we must destroy the surplus elements:
template
void vector::resize(size_type newsize, const T& val)
{
reserve(newsize);
if (size()uninitialized_fill(elem+size(),elem+newsize,val);
else
destroy(elem
...
space = vb
...
elem+newsize;
}

// construct new elements: [size():newsize)
// destroy sur plus elements: [newsize:size())

There is no standard destroy(), but that easily written:
template
void destroy(In b, In e)
{
for (; b!=e; ++b)
// destroy [b:e)
b−>˜T();
}

13
...
4
...
alloc
...
elem[size()],val);
++vb
...
If that happens,

386

Exception Handling

Chapter 13

the value of the vector remains unchanged, with space left unincremented
...

This definition of push_back() contains two ‘‘magic numbers’’ (2 and 8)
...
As it happens, these are not unreasonable or uncommon values
...
The factor two is larger than the mathematically optimal factor to minimize average
memory use (1
...


13
...
4
...

The approach of gaining exception safety through ordering and the RAII technique (§13
...
More
problems with exception safety arise from a programmer ordering code in unfortunate ways than
from lack of specific exception-handling code
...

Exceptions introduce possibilities for surprises in the form of unexpected control flows
...
It is relatively simple to look at such code and
ask, ‘‘Can this line of code throw an exception, and what happens if it does?’’ For large functions
with complicated control structures, such as complicated conditional statements and nested loops,
this can be hard
...
3)
...
Simple, stylized code is easier to understand, easier to get
right, and easier to generate good code for
...
The standard does not require an implementation
to be exactly like the one presented here
...

tialized_copy())
...
7 Advice
[1]
[2]
[3]
[4]

Develop an error-handling strategy early in a design; §13
...

Throw an exception to indicate that you cannot perform an assigned task; §13
...
1
...
1
...
2
...
1
...


Section 13
...
1
...

Use hierarchical error handling; §13
...
6
...
1
...

Don’t try to catch every exception in every function; §13
...
6
...
2, §13
...

Provide the strong guarantee unless there is a reason not to; §13
...
6
...
2
...
2
...
3
...
1
...

Use the ‘‘Resource Acquisition Is Initialization’’ technique to manage resources; §13
...

Minimize the use of try-blocks; §13
...

Not every program needs to be exception-safe; §13
...

Use ‘‘Resource Acquisition Is Initialization’’ and exception handlers to maintain invariants;
§13
...
2
...

Prefer proper resource handles to the less structured finally; §13
...
1
...
4
...
4
...
4
...
5
...
1
Don’t use exception specification; §13
...
1
...

Catch exceptions that may be part of a hierarchy by reference; §13
...
2
...
5
...
2
...
5
...
2, §13
...
2
...

Don’t destroy information before you have its replacement ready; §13
...

Leave operands in valid states before throwing an exception from an assignment; §13
...

Never let an exception escape from a destructor; §13
...

Keep ordinary code and error-handling code separate; §13
...
1, §13
...
4
...

Beware of memory leaks caused by memory allocated by new not being released in case of
an exception; §13
...

Assume that every exception that can be thrown by a function will be thrown; §13
...

A library shouldn’t unilaterally terminate a program
...
4
...
Instead, throw an exception and let a caller decide; §13
...
3
...
D
...
Safety; Namespace Aliases; Namespace Composition; Composition and
Selection; Namespaces and Overloading; Versioning; Nested Namespaces; Unnamed Namespaces; C Headers
Advice

14
...
Functions (§2
...
1, Chapter 12) and
classes (§3
...
4, Chapter 15) provide coarser grain
...
C++ does not provide a single language feature supporting the
notion of a module; there is no module construct
...

This chapter and the next deal with the coarse structure of a program and its physical representation as source files
...

Consider some of the problems that can arise when people fail to design for modularity
...
*/ };
class Line : public Shape { /*
...
*/ };
class Text : public Shape { /*
...
*/ };
class Word { /*
...
*/ };
class Text { /*
...

Assume (realistically enough) that the facilities of Graph_lib are defined in a header (§2
...
1),
Graph_lib
...
h
...
h"
#include "Text_lib
...


Just #includeing those headers causes a slurry of error messages: Line, Text, and open() are defined
twice in ways that a compiler cannot disambiguate
...

There are many techniques for dealing with such name clashes
...
g
...
g
...
Each of these techniques (also known as ‘‘workarounds’’ and ‘‘hacks’’) works in some cases, but they are not general and can be inconvenient to
use
...
4)
...
2

Namespaces

391

14
...
The members of a namespace are in the
same scope and can refer to each other without special notation, whereas access from outside the
namespace requires explicit notation
...
g
...
For example, we might call the graph
library Graph_lib:
namespace Graph_lib {
class Shape { /*
...
*/ };
class Poly_line: public Shape { /*
...
*/ };

// connected sequence of lines
// text label

Shape operator+(const Shape&, const Shape&);

// compose

Graph_reader open(const char∗);

// open file of Shapes

}

Similarly, the obvious name for our text library is Text_lib:
namespace Text_lib {
class Glyph { /*
...
*/ };
class Line { /*
...
*/ };

// sequence of Glyphs
// sequence of Words
// sequence of Lines

File∗ open(const char∗);

// open text file

Word operator+(const Line&, const Line&);

// concatenate

}

As long as we manage to pick distinct namespace names, such as Graph_lib and Text_lib (§14
...
2),
we can now compile the two sets of declarations together without name clashes
...
They should be seen as a logical unit, for example, ‘‘the graphics library’’ or
‘‘the text manipulation library,’’ similar to the way we consider the members of a class
...

A namespace is a (named) scope
...
For example:
class Glyph { /*
...
*/ };
namespace Text_lib {
class Glyph { /*
...
*/ };

// sequence of Glyphs

392

Namespaces

Chapter 14

class Line { /*
...
*/ }; // sequence of Lines
File∗ open(const char∗);

// open text file

Word operator+(const Line&, const Line&);

// concatenate

}
Glyph glyph(Line& ln, int i);

// ln[i]

Here, the

Word and Line in the declaration of Text_lib::operator+() refer to Text_lib::Word and
Text_lib::Line
...
Conversely, the Glyph and
Line in the declaration of the global glyph() refer to the global ::Glyph and ::Line
...


To refer to members of a namespace, we can use its fully qualified name
...
2
...
2
...
2
...


14
...
1 Explicit Qualification
A member can be declared within a namespace definition and defined later using the namespacename :: member-name notation
...

}

// definition

We cannot declare a new member of a namespace outside a namespace definition using the qualifier
syntax (§iso
...
3
...
2)
...
For example:

Section 14
...
1

Explicit Qualification

void Parser::logical(bool);
double Parser::trem(bool);
double Parser::prim(int);

393

// error : no logical() in Parser
// error : no trem() in Parser (misspelling)
// error : Parser ::prim() takes a bool argument (wrong type)

A namespace is a scope
...
Thus, ‘‘namespace’’ is a very
fundamental and relatively simple concept
...
The global scope is a namespace and can be explicitly referred to using ::
...
2)
...
2
...
Consider:
#include
#include
#include
std::vector split(const std::string& s)
// split s into its whitespace-separated substrings
{
std::vector res;
std::istringstream iss(s);
for (std::string buf; iss>>buf;)
res
...
In particular, we repeat std::string four
times in this small example
...
push_back(buf);
return res;
}

A using-declaration introduces a synonym into a scope
...

When used for an overloaded name, a using-declaration applies to all the overloaded versions
...
3
...


14
...
3 using-Directives
In the split() example (§14
...
2), we still had three uses of std:: left after introducing a synonym for
std::string
...
That can be
achieved by providing a using-declaration for each name from the namespace, but that’s tedious
and requires extra work each time a new name is added to or removed from the namespace
...
For example:
using namespace std;

// make every name from std accessible

vector split(const string& s)
// split s into its whitespace-separated substrings
{
vector res;
istringstream iss(s);
for (string buf; iss>>buf;)
res
...
4)
...
This is the technique used to access standard-library facilities throughout this book
...


Section 14
...
3

using-Directives

395

Within a function, a using-directive can be safely used as a notational convenience, but care
should be taken with global using-directives because overuse can lead to exactly the name clashes
that namespaces were introduced to avoid
...
*/ };
class Line : Shape { /*
...
*/ };
class Text : Shape { /*
...
*/ };
class Word { /*
...
*/ };
class Text { /*
...
In particular, we can use names that do not clash, such as Glyph and Shape
...
For example:
Text txt;
File∗ fp = open("my_precious_data");

// error : ambiguous
// error : ambiguous

Consequently, we must be careful with using-directives in the global scope
...
g
...


14
...
4 Argument-Dependent Lookup
A function taking an argument of user-defined type X is more often than not defined in the same
namespace as X
...
For example:

396

Namespaces

Chapter 14

namespace Chrono {
class Date { /*
...


// make string representation

}
void f(Chrono::Date d, int i)
{
std::string s = format(d);
std::string t = format(i);
}

// Chrono::format()
// error : no format() in scope

This lookup rule (called argument-dependent lookup or simply ADL) saves the programmer a lot of
typing compared to using explicit qualification, yet it doesn’t pollute the namespace the way a
using-directive (§14
...
3) can
...
2
...
3
...

Note that the namespace itself needs to be in scope and the function must be declared before it
can be found and used
...
For example:
void f(Chrono::Date d, std::string s)
{
if (d == s) {
//
...

}
}

In such cases, we look for the function in the scope of the call (as ever) and in the namespaces of
every argument (including each argument’s class and base classes) and do the usual overload resolution (§12
...
In particular, for the call d==s, we look for operator== in the
scope surrounding f(), in the std namespace (where == is defined for string), and in the Chrono
namespace
...
See also §18
...
5
...
2
...
2
...
For example:
namespace N {
struct S { int i };
void f(S);
void g(S);
void h(int);
}

Section 14
...
4

Argument-Dependent Lookup

397

struct Base {
void f(N::S);
};
struct D : Base {
void mf();
void g(N::S x)
{
f(x);
// call Base::f()
mf(x);
// call D::mf()
h(1);
// error: no h(int) available
}
};

In the standard, the rules for argument-dependent lookup are phrased in terms of associated namespaces (§iso
...
4
...
Basically:
• If an argument is a class member, the associated namespaces are the class itself (including
its base classes) and the class’s enclosing namespaces
...

• If an argument is a built-in type, there are no associated namespaces
...
For example, the search for a declaration of a function f() does not have a
preference for functions in a namespace in which f() is called (the way it does for functions in a
class in which f() is called):
namespace N {
template
void f(T, int); // N::f()
class X { };
}
namespace N2 {
N::X x;
void f(N::X, unsigned);
void g()
{
f(x,1);
}

// calls N::f(X,int)

}

It may seem obvious to choose N2::f(), but that is not done
...

Conversely, examples have been seen where a function in the caller’s namespace is chosen but the
programmer expected a better function from a known namespace to be used (e
...
, a standard-library
function from std)
...
See also §26
...
6
...
2
...
For example:
namespace A {
int f();
// now A has member f()
}
namespace A {
int g();
// now A has two members, f() and g()
}

That way, the members of a namespace need not be placed contiguously in a single file
...
For example, consider a header
file written without the use of namespaces:
// my header:
void mf();
void yf();
int mg();
//
...
This
can be rewritten without reordering the declarations:
// my header:
namespace Mine {
void mf();
// my function
//
...

}

When writing new code, I prefer to use many smaller namespaces (see §14
...
However, that is often impractical when converting major pieces of software to use namespaces
...
3 provides an example
...
4
...


Section 14
...
3 Modularization and Interfaces
Any realistic program consists of a number of separate parts
...

Consider the desk calculator example from §10
...
It can be viewed as composed of five parts:
[1] The parser, doing syntax analysis: expr(), term(), and prim()
[2] The lexer, composing tokens out of characters: Kind, Token, Token_stream, and ts
[3] The symbol table, holding (string,value) pairs: table
[4] The driver: main() and calculate()
[5] The error handler: error() and number_of_errors
This can be represented graphically:
driver
error handler

parser
lexer
symbol table

where an arrow means ‘‘using
...
In fact, the calculator was conceived as three parts, with the driver
and error handler added for completeness
...
Ideally, most of the details of a module are unknown to its users
...
For example, the parser directly relies on the lexer’s interface
(only), rather than on the complete lexer
...
This can be presented graphically like this:
driver
parser interface

parser implementation

lexer interface

lexer implementation

symbol table interface

error handler

symbol table implementation

A dashed line means ‘‘implements
...
That done, the code will be simple, efficient, comprehensible, maintainable, etc
...


400

Namespaces

Chapter 14

The following subsections show how the logical structure of the desk calculator program can be
made clear, and §15
...
The calculator is a tiny program, so in ‘‘real life’’ I wouldn’t bother using namespaces and separate compilation (§2
...
1, §15
...
Making the structure of
the calculator explicit is simply an illustration of techniques useful for larger programs without
drowning in code
...

Error handling permeates the structure of a program
...
C++ provides exceptions to decouple the
detection and reporting of errors from the handling of errors (§2
...
3
...

There are many more notions of modularity than the ones discussed in this chapter and the next
...
3, Chapter 41) or
processes to represent important aspects of modularity
...
I consider these notions of modularity largely independent and orthogonal
...
The hard problem is to provide safe,
convenient, and efficient communication across module boundaries
...
3
...
That is, if some declarations logically belong together according to some criteria, they can be put in a common namespace to
express that fact
...
For
example, the declarations of the parser from the desk calculator (§10
...
1) may be placed in a namespace Parser:
namespace Parser {
double expr(bool);
double prim(bool get) { /*
...
*/ }
double expr(bool get) { /*
...
2
...

The input part of the desk calculator could also be placed in its own namespace:
namespace Lexer {
enum class Kind : char { /*
...
*/ };
class Token_stream { /*
...
3
...
*/ }
}
int main() { /*
...
*/ }
}

This use of namespaces makes explicit what the lexer and the parser provide to a user
...
If function
bodies are included in the declaration of a realistically sized namespace, you typically have to wade
through screenfuls of information to find what services are offered, that is, to find the interface
...
I don’t consider that a good solution
...

Here is a version of the Parser with the interface separated from the implementation:
namespace Parser {
double prim(bool);
double term(bool);
double expr(bool);
}
double Parser::prim(bool get) { /*
...
*/ }
double Parser::expr(bool get) { /*
...
Users will see only the interface containing declarations
...

Ideally, every entity in a program belongs to some recognizable logical unit (‘‘module’’)
...
The exception is main(), which must be global in order for
the compiler to recognize it as special (§2
...
1, §15
...


402

Namespaces

Chapter 14

14
...
2 Implementations
What will the code look like once it has been modularized? That depends on how we decide to
access code in other namespaces
...
However, for names in other namespaces, we
have to choose among explicit qualification, using-declarations, and using-directives
...
If we use explicit qualification, we get:
double Parser::prim(bool get)
{
if (get) Lexer::ts
...
current()
...
current()
...
get();
return v;
}
case Lexer::Kind::name:
{
double& v = Table::table[Lexer::ts
...
string_value];
if (Lexer::ts
...
kind == Lexer::Kind::assign) v = expr(true); // ’=’ seen: assignment
return v;
}
case Lexer::Kind::minus:
// unar y minus
return −prim(true);
case Lexer::Kind::lp:
{
double e = expr(true);
if (Lexer::ts
...
kind != Lexer::Kind::rp) return Error::error(" ')' expected");
Lexer::ts
...
I didn’t use Parser:: because that would be
redundant within namespace Parser
...
3
...
get();

Implementations

403

// handle primaries

switch (ts
...
kind) {
case Kind::number:
// floating-point constant
{
double v = ts
...
number_value;
ts
...
current()
...
get()
...
current()
...
get();
// eat ’)’
return e;
}
default:
return error("primary expected");
}
}

My guess is that the using-declarations for Lexer:: were worth it, but that the value of the others was
marginal
...

So, the tradeoff among explicit qualification, using-declarations, and using-directives must be
made on a case-by-case basis
...

[2] If some qualification is common for a particular name from a namespace, use a using-declaration for that name
...

Don’t use explicit qualification for names in the same namespace as the user
...
3
...
Instead, that Parser declares the set of declarations that is needed to
write the individual parser functions conveniently
...

The functions implementing the parser should see whichever interface we decided on as the best
for expressing those functions’ shared environment
...

We could give the user’s interface and the implementer’s interface different names, but (because
namespaces are open; §14
...
5) we don’t have to
...
3
...
Had we decided to use a separate implementation namespace, the design would not have
looked different to users:

Section 14
...
3

Interfaces and Implementations

405

namespace Parser { // user interface
double expr(bool);
}
namespace Parser_impl {
using namespace Parser;

// implementer interface

double prim(bool);
double term(bool);
double expr(bool);
using namespace Lexer; // use all facilities offered by Lexer
using Error::error;
using Table::table;
}

or graphically:
Parser

(user interface)
Parser_impl

Driver

code

(implementer interface)

Parser

code

For larger programs, I lean toward introducing _impl interfaces
...
Had this
interface been for a realistically sized module in a real system, it would change more often than the
interface seen by users
...


14
...
This section examines technical aspects of
composing code out of namespaces
...
4
...
Safety
A using-declaration adds a name to a local scope
...
For example:
namespace X {
int i, j, k;
}

406

Namespaces

Chapter 14

int k;
void f1()
{
int i = 0;
using namespace X;
i++;
j++;
k++;
::k++;
X::k++;
}
void f2()
{
int i = 0;
using X::i;
using X::j;
using X::k;
i++;
j++;
k++;

// make names from X accessible
// local i
// X::j
// error : X’s k or the global k?
// the global k
// X’s k

// error: i declared twice in f2()
// hides global k

// X::j
// X::k

}

A locally declared name (declared either by an ordinary declaration or by a using-declaration) hides
nonlocal declarations of the same name, and any illegal overloading of the name is detected at the
point of declaration
...
Global names are not given preference over names
from namespaces made accessible in the global scope
...

When libraries declaring many names are made accessible through using-directives, it is a significant advantage that clashes of unused names are not considered errors
...
4
...

}
A::String s1 = "Grieg";
A::String s2 = "Nielsen";

However, long namespace names can be impractical in real code:

Section 14
...
2

namespace American_Telephone_and_Telegraph {
//
...
For example:
namespace Lib = Foundation_library_v2r11;
//
...
By using
Lib rather than Foundation_library_v2r11 directly, you can update to version ‘‘v3r02’’ by changing
the initialization of the alias Lib and recompiling
...
On the other hand, overuse of aliases (of any kind) can lead to confusion
...
4
...
For example:
namespace His_string {
class String { /*
...

}
namespace Her_vector {
template
class Vector { /*
...

}

408

Namespaces

Chapter 14

namespace My_lib {
using namespace His_string;
using namespace Her_vector;
void my_fct(String&);
}

Given this, we can now write the program in terms of My_lib:
void f()
{
My_lib::String s = "Byron";
//
...

my_fct(vs[5]);
//
...

Only if we need to define something do we need to know the real namespace of an entity:
void My_lib::fill(char c)
{
//
...

}

// OK: fill() declared in His_string

void My_lib::my_fct(String& v)// OK: String is My_lib::String, meaning His_string::String
{
//
...

Together with the #include mechanism (§15
...
2), the composition techniques presented here and in
the following subsections provide strong support for this
...
4
...
4
...
With these mechanisms, we can provide access to a
variety of facilities in such a way that we resolve name clashes and ambiguities arising from their
composition
...
*/ };
template
class Vector { /*
...

}
namespace Her_lib {
template
class Vector { /*
...
*/ };
//
...
*/ };
//
...
4
...
Consequently, a user of My_lib will see the name clashes for String and Vector
resolved in favor of His_lib::String and Her_lib::Vector
...

Usually, I prefer to leave a name unchanged when including it into a new namespace
...
However, sometimes a new name
is needed or simply nice to have
...
*/ };
//
...
4
...
5)
...
4
...
3) works across namespaces
...
For example:
// old A
...

// old B
...

// old user
...
h"
#include "B
...
h
}

This program can be upgraded to a version using namespaces without changing the actual code:
// new A
...

}
// new B
...

}

Section 14
...
5

Namespaces and Overloading

411

// new user
...
h"
#include "B
...
h

Had we wanted to keep user
...
However, it is usually best to avoid using-directives in header files, because
putting them there greatly increases the chances of name clashes
...
For example, people
often wonder why they have to explicitly mention a sequence to manipulate a container using a
standard-library algorithm
...
begin(),v
...
2), but manipulating a container is by far the most common case
...
begin(),c
...
begin(),c
...
Those are of
course implemented using std::sort() from
...
begin(),v
...
begin(),v
...
2
...
However, we would then not find
the standard sort()s for our own containers defined outside std
...
4
...

Consider a widely used interface, say, an ISO C++ standard header
...
Functions may have been added,
classes renamed, proprietary extensions (that should never have been there) removed, types
changed, templates modified
...
Needless to say, breaking such code will cause howls of outrage, as
will the absence of a new and better version
...
Consequently, there is a way of selecting between two versions that simply and obviously guarantees that a user sees exactly one particular version
...
*/ };
}

Section 14
...
6

Versioning

413

namespace V3_0 {
//
...
*/ };
}
}

Here, Popular contains three subnamespaces, each defining a version
...
So we can write:
using namespace Popular;
void f()
{
f(1);
V3_0::f(1);
V2_4_2::f(1);
}

// Popular ::V3_2::f(int)
// Popular ::V3_0::f(double)
// Popular ::V2_4_2::f(double)

template
Popular::C { /*
...
Also, naively using this way of handling
versioning would involve a lot of replication (of common code in the different versions)
...
For example:
// file V3_common:
//
...

// file V3_2:
namespace V3_2 { // V3_2 provides the default meaning of Popular
double f(double);
int f(int);
template
class C { /*
...
h:
namespace V3_0 {
#include "V3_common"
}

414

Namespaces

Chapter 14

// file Popular
...
h"
#include "V3_0
...
h"
}

I do not recommend such intricate use of header files unless it is really necessary
...
2
...
Sadly, I have seen worse
...
The only example I can think
of that is completely impossible to do by other means is the specialization of a template explicitly
using the namespace name (e
...
, Popular::C)
...
Also, a solution based on a combination of other techniques is less obviously completely right
...
4
...
all my declarations
...
Thus, nested namespaces are allowed
...
For example:
void h();
namespace X {
void g();
//
...

}
}

The usual scope and qualification rules apply:
void X::Y::ff()
{
f(); g(); h();
}

Section 14
...
7

void X::g()
{
f();
Y::f();
}
void h()
{
f();
Y::f();
X::f();
X::Y::f();
}

Nested Namespaces

415

// error: no f() in X
// OK

// error: no global f()
// error: no global Y
// error: no f() in X
// OK

For examples of nested namespaces in the standard library, see
(§35
...
3)
...
2) and

rel_ops

14
...
8 Unnamed Namespaces
It is sometimes useful to wrap a set of declarations in a namespace simply to protect against the
possibility of name clashes
...
For example:
#include "header
...
*/ }
int g() { /*
...
In that
case, we can simply leave the namespace without a name:
#include "header
...
*/ }
int g() { /*
...
Consequently, an unnamed namespace has an implied using-directive
...
*/ }
int g() { /*
...
In particular,
unnamed namespaces in different translation units are different
...


14
...
9 C Headers
Consider the canonical first C program:
#include ...
Making standard libraries special cases isn’t a
good idea either
...
In fact, the calculator program (§10
...

One way to provide the standard C I/O facilities in a namespace would be to place the declarations from the C header stdio
...
);
//
...
h:
#include
using namespace std;

This ...
Unfortunately, the using-directive makes
every name from namespace std accessible in the global namespace
...
h>
vector v2;

// carefully avoids polluting the global namespace
// error: no ‘‘vector’’ in global scope
// contains a ‘‘using namespace std;’’
// oops: this now works

So the standard requires that ...
This
can be done by providing a using-declaration for each declaration in :
// stdio
...


Section 14
...
9

C Headers

417

Another advantage is that the using-declaration for printf() prevents a user from (accidentally or
deliberately) defining a nonstandard printf() in the global scope
...
I also use them for essential foundation libraries, such as the ISO
C++ standard library (std)
...

The relationship between namespaces and linkage is described in §15
...
5
...
5 Advice
[1]
[2]
[3]

Use namespaces to express logical structure; §14
...
1
...
3
...

Design a namespace so that you can conveniently use it without accidentally gaining access
to unrelated namespaces; §14
...
3
...
4
...

[5] If necessary, use namespace aliases to abbreviate long namespace names; §14
...
2
...
2
...
2
...

[7] Use separate namespaces for interfaces and implementations; §14
...
3
...
4
...
4
...

[10] Use using-directives for transition, for foundational libraries (such as std), or within a local
scope; §14
...
9
...
2
...


This page intentionally left blank

15
Source Files and Programs
Form must follow function
...
1 Separate Compilation
Any realistic program consists of many logically separate components (e
...
, namespaces; Chapter
14)
...
Our task is to devise a physical
structure (set of files) for the program that represents the logical components in a consistent, comprehensible, and flexible manner
...
g
...
g
...
A file is the traditional unit
of storage (in a file system) and the traditional unit of compilation
...
However, the discussion here will concentrate on systems that employ the traditional use of files
...
In particular, the code for the
standard libraries and the operating system is typically not supplied in source form as part of a

420

Source Files and Programs

Chapter 15

user’s program
...
The way a program is organized into files can help
emphasize its logical structure, help a human reader understand the program, and help the compiler
enforce that logical structure
...

For even a moderately sized program, the amount of time spent recompiling can be significantly
reduced by partitioning the program into files of suitable size
...
The file is then preprocessed; that is, macro processing (§12
...
4
...
2
...
The result of preprocessing is called a translation unit
...
In this book, I differentiate between source file and translation unit
only where necessary to distinguish what the programmer sees from what the compiler considers
...
The declarations in a program consisting of many separately compiled parts must be consistent in exactly
the same way the declarations in a program consisting of a single source file must be
...
In particular, the linker can detect many kinds of inconsistencies
...
A linker is sometimes (confusingly) called a loader
...
Alternatively, new code can be added to the running program (‘‘dynamically linked’’) later
...
The physical separation of a program into separate files should be guided by the logical
structure of the program
...
However, the logical and physical structures of a program need not be identical
...
3
...

Here, we will first consider some technicalities relating to linking and then discuss two ways of
breaking the desk calculator (§10
...
3
...


15
...

It is the programmer’s task to ensure that every namespace, class, function, etc
...
For example, consider two files:
// file1
...
2

Linkage

421

// file2
...
cpp are the ones defined in file1
...
The keyword extern indicates
that the declaration of x in file2
...
3)
...
An object must be defined exactly once in a program
...
For example:
// file1
...
cpp:
int x;
extern double b;
extern int c;

// means ‘‘int x = 0;’’

There are three errors here: x is defined twice, b is declared twice with different types, and c is
declared twice but not defined
...
Many, however, are detectable by the linker
...
However, the
inconsistent declarations of b are uncaught on popular implementations, and the missing definition
of c is typically only caught if c is used
...
3
...
1)
...
2)
...
3
...
For example:
// file1
...
All the names in the previous examples have external linkage
...

For example:
static int x1 = 1;
const char x2 = 'a';

// internal linkage: not accessible from other translation units
// internal linkage: not accessible from other translation units

When used in namespace scope (including the global scope; §14
...
1), the keyword static (somewhat illogically) means ‘‘not accessible from other source files’’ (i
...
, internal linkage)
...
The keyword const implies default internal linkage, so if you wanted x2 to have external
linkage, you need to precede its definitions with extern:

422

Source Files and Programs

int x1 = 1;
extern const char x2 = 'a';

Chapter 15

// external linkage: accessible from other translation units
// external linkage: accessible from other translation units

Names that a linker does not see, such as the names of local variables, are said to have no linkage
...
1
...
2
...
2
...
Consequently, the following example isn’t just bad taste; it is illegal:
// file1
...
cpp:
inline int f(int i) { return i+1; }

Unfortunately, this error is hard for an implementation to catch, and the following – otherwise perfectly logical – combination of external linkage and inlining is banned to make life simpler for
compiler writers:
// file1
...
cpp:
extern inline int g(int i) { return i+1; }
//
...
2
...
For example:
// h
...
cpp:
#include "h
...
cpp:
#include "h
...


By default, const objects (§7
...
4), type aliases (§6
...
3
...
Consequently, this example is
legal (although potentially confusing):
// file1
...
cpp:
using T = double;
const int x = 8;
constexpr T c2 = x+9;

Section 15
...
2
...

A const can be given external linkage by an explicit declaration:
// file1
...
cpp:
extern const int a;
void g()
{
cout << a << '\n';
}

Here, g() will print 77
...
7
...
2
...
In particular, it is hard to know where in a program they are used, and they can be a source of data races in
multi-threaded programs (§41
...
4), leading to very obscure bugs
...

If you must use global variables, at least restrict their use to a single source file
...

[2] Declare an entity static
...
4
...
The
effect of an unnamed namespace is very similar to that of internal linkage
...
cpp:
namespace {
class X { /*
...

}
// file2
...
*/ };
void f();
int i;
//
...
cpp is not the same function as the f() in file2
...
Having a name local to a
translation unit and also using that same name elsewhere for an entity with external linkage is asking for trouble
...
2
...
That’s an unfortunate leftover from the earliest days of C
...
2
...
, must be consistent
...

One imperfect but simple method of achieving consistency for declarations in different translation
units is to #include header files containing interface information in source files containing
executable code and/or data definitions
...
Consider:
#include "to_be_included"

The

#include-directive replaces the line in which the #include appears with the contents of the file
to_be_included
...

To include standard-library headers, use the angle brackets, < and >, around the name instead of
quotes
...
h"

// from standard include directory
// from current directory

Unfortunately, spaces are significant within the < > or " " of an include directive:
#include < iostream >

// will not find

It seems extravagant to recompile a source file each time it is included somewhere, but the text can
be a reasonably dense encoding for program interface information, and the compiler need only analyze details actually used (e
...
, template bodies are often not completely analyzed until instantiation
time; §26
...
Furthermore, most modern C++ implementations provide some form of (implicit or
explicit) precompiling of header files to minimize the work needed to handle repeated compilation
of the same header
...
∗/ }
inline namespace N { /∗
...
∗/ };
extern int strlen(const char∗);
inline char get(char∗ p) { /∗
...
141593;
constexpr float pi2 = pi∗pi;
enum class Light { red, yellow, green };
class Matrix;
using value_type = long;

Section 15
...
2

Header Files

Compile-time assertions
Include directives
Macro definitions
Conditional compilation directives
Comments

425

static_assert(4<=sizeof(int),"small ints");
#include
#define VERSION 12
...
It is simply a
reasonable way of using the #include mechanism to express the physical structure of a program
...
∗/ }
using namespace Foo;

Including a header containing such definitions will lead to errors or (in the case of the using-directive) to confusion
...
h, and files containing function or
data definitions are suffixed by
...
They are therefore often referred to as ‘‘
...
cpp
files,’’ respectively
...
c,
...
cxx,
...
hh, and hpp are also found
...

The reason for recommending that the definition of simple constants, but not the definition of
aggregates, be placed in header files is that it is hard for implementations to avoid replication of
aggregates presented in several translation units
...

It is wise not to be too clever about the use of #include
...

• #include only complete declarations and definitions
...
2
...

• Place all #includes before other code to minimize unintended dependencies
...

• Minimize the use of names (especially aliases) not local to a header in a header
...


15
...
3 The One-Definition Rule
A given class, enumeration, and template, etc
...

From a practical point of view, this means that there must be exactly one definition of, say, a
class residing in a single file somewhere
...

For example, the definition of a class may be composed through macro expansion (ugh!), and a definition of a class may be textually included in two source files by #include directives (§15
...
2)
...

Consequently, the rule in the standard that says that there must be a unique definition of a class,
template, etc
...
This rule is commonly referred to as the one-definition rule (‘‘the ODR’’)
...

For example:
// file1
...
cpp:
struct S { int a; char b; };
void f(S∗ p) { /*
...

However, it is unwise to write out a definition twice like that
...
cpp will
naturally assume that the definition of S in file2
...
This could introduce a hard-to-detect error
...
For example:
// s
...
cpp:
#include "s
...
cpp:
#include "s
...
*/ }

or graphically:
s
...
cpp:

struct S { int a; char b; };
void f(S∗);

#include "s
...
cpp:

#include "s
...
∗/ }

Section 15
...
3

The One-Definition Rule

427

Here are examples of the three ways of violating the ODR:
// file1
...

// file1
...
cpp:
struct S2 { int a; char bb; };

// error

This is an error because S2 is used to name classes that differ in a member name
...
cpp:
typedef int X;
struct S3 { X a; char b; };
// file2
...

Checking against inconsistent class definitions in separate translation units is beyond the ability
of most C++ implementations
...
Unfortunately, the technique of placing shared definitions in headers and #includeing
them doesn’t protect against this last form of ODR violation
...
h:
struct S { Point a; char b; };
// file1
...
h"
//
...
cpp:
class Point { /*
...
h"
//
...
For
example, if class Point had been declared in the s
...

A template definition can be #included in several translation units as long as the ODR is adhered
to
...


428

Source Files and Programs

Chapter 15

15
...
4 Standard-Library Headers
The facilities of the standard library are presented through a set of standard headers (§4
...
2, §30
...

No suffix is needed for standard-library headers; they are known to be headers because they are
included using the #include<
...
The absence of a
...
A header such as is usually stored as a text
file called map
...
On the other hand, standard headers are not required
to be stored in a conventional manner
...
For example, an implementation might have knowledge of the standard math library (§40
...

For each C standard-library header ...

For example, #include provides what #include ...
A typical stdio
...
2
...
1
...
2
...
*/
int printf(const char∗,
...
*/
#ifdef __cplusplus
}
}
//
...

#endif

That is, the actual declarations are (most likely) shared, but linkage and namespace issues must be
addressed to allow C and C++ to share a header
...
6
...


15
...
5 Linkage to Non-C++ Code
Typically, a C++ program contains parts written in other languages (e
...
, C or Fortran)
...
g
...
Cooperation can be difficult between program fragments written
in different languages and even between fragments written in the same language but compiled with
different compilers
...
To help, one
can specify a linkage convention to be used in an extern declaration
...
2
...

The extern "C" directive is particularly useful because of the close relationship between C and
C++
...
Often, extern
"C" is used to link to Fortran and assembler routines that happen to conform to the conventions of a
C implementation
...
In particular, a function declared extern "C" still obeys the C++ type-checking and argument conversion rules and not the weaker C rules
...
Consequently, there is a mechanism to
specify linkage to a group of declarations
...

}

This construct, commonly called a linkage block, can be used to enclose a complete C header to
make a header suitable for C++ use
...
h>
}

This technique is commonly used to produce a C++ header from a C header
...
6
...

#ifdef __cplusplus
}
#endif

430

Source Files and Programs

Chapter 15

The predefined macro name __cplusplus (§12
...
2) is used to ensure that the C++ constructs are
edited out when the file is used as a C header
...
3
...
4
...
To declare but not define a variable,
you must apply the keyword extern directly in the declaration
...
However, it is a simple consequence of keeping the meaning
unchanged when adding "C" to an extern-declaration and the meaning of a file unchanged when
enclosing it in a linkage block
...
The namespace will affect the way the
name is accessed in the C++ program, but not the way a linker sees it
...
3)
...
Unfortunately, the same flexibility is not available to us for
headers defining functions with C++ linkage in the global namespace
...


15
...
6 Linkage and Pointers to Functions
When mixing C and C++ code fragments in one program, we sometimes want to pass pointers to
functions defined in one language to functions defined in the other
...
However, such commonality cannot in general be assumed, so care must
be taken to ensure that a function is called the way it expects to be called
...
This makes all kinds of
strange – and occasionally essential – combinations of linkage possible
...
2
...
However, even for compatible C and C++ implementations, std::function (§33
...
3) or lambdas with any form of capture (§11
...
3) cannot cross the language barrier
...
3 Using Header Files
To illustrate the use of headers, I present a few alternative ways of expressing the physical structure
of the calculator program (§10
...
3
...


15
...
1 Single-Header Organization
The simplest solution to the problem of partitioning a program into several files is to put the definitions in a suitable number of
...
, needed for
them to cooperate in a single
...
cpp file #includes
...

For the calculator program, we might use five
...
cpp, parser
...
cpp,
error
...
cpp – to hold function and data definitions
...
h holds the declarations of every name used in more than one
...
h:
#include
#include
#include
namespace Parser {
double expr(bool);
double term(bool);
double prim(bool);
}
namespace Lexer {
enum class Kind : char {
name, number, end,
plus='+', minus='−', mul='∗', div='/’, print=';', assign='=', lp='(', rp=')'
};
struct Token {
Kind kind;
string string_value;
double number_value;
};
class Token_stream {
public:
Token(istream& s) : ip{&s}, owns(false}, ct{Kind::end} { }
Token(istream∗ p) : ip{p}, owns{true}, ct{Kind::end} { }
˜Token() { close(); }
Token get();
Token& current();

// read and return next token
// most recently read token

void set_input(istream& s) { close(); ip = &s; owns=false; }
void set_input(istream∗ p) { close(); ip = p; owns = true; }
private:
void close() { if (owns) delete ip; }
istream∗ ip;
// pointer to an input stream
bool owns;
// does the Token_stream own the istream?
Token ct {Kind::end};
// current_token
};
extern Token_stream ts;
}

Chapter 15

Section 15
...
1

Single-Header Organization

433

namespace Table {
extern map table;
}
namespace Error {
extern int no_of_errors;
double error(const string& s);
}
namespace Driver {
void calculate();
}

The keyword extern is used for every variable declaration to ensure that multiple definitions do not
occur as we #include dc
...
cpp files
...
cpp files
...
h, but I did not add declarations (such as using-declarations) needed only for the convenience of an individual
...

Leaving out the actual code, lexer
...
cpp:
#include "dc
...
h

Lexer::Token_stream ts;
Lexer::Token Lexer::Token_stream::get() { /*
...
*/ }

I used explicit qualification, Lexer::, for the definitions rather that simply enclosing them all in
namespace Lexer { /*
...
On the other hand, had I
wanted to add members to Lexer that were not part of its interface, I would have had to reopen the
namespace (§14
...
5)
...
For example, when compiling lexer
...
h
//
...

};
}

434

Source Files and Programs

Chapter 15

//
...
*/ }

This ensures that the compiler will detect any inconsistencies in the types specified for a name
...
cpp would have failed with a type-mismatch error
...
If a declaration is missing, some
...

File parser
...
cpp:
#include "dc
...
*/ }
double Parser::term(bool get) { /*
...
*/ }

File table
...
cpp:
#include "dc
...

File error
...
cpp:
#include "dg
...
*/ }

Finally, file main
...
cpp:
#include "dc
...
h

void Driver::calculate() { /*
...
*/ }

To be recognized as the main() of the program, main() must be a global function (§2
...
1, §15
...


Section 15
...
1

Single-Header Organization

435

The physical structure of the system can be presented like this:










lexer
...
cpp

dc
...
cpp

parser
...
cpp

The headers on the top are all headers for standard-library facilities
...
For tiny programs,
the structure can be simplified by moving all #include directives to the common header
...
cpp and table
...
cpp would often be excessive
...
Note that when namespaces are used, the logical
structure of the program is still represented within dc
...
If namespaces are not used, the structure is
obscured, although comments can be a help
...
A change to the common header forces recompilation of the whole program, and updates of that single header by several programmers are error-prone
...


15
...
2 Multiple-Header Organization
An alternative physical organization lets each logical module have its own header defining the facilities it provides
...
cpp file then has a corresponding
...
Each
...
h file and usually also other
...
This physical organization corresponds to the logical organization of a module
...
h file, the interface for implementers is put into a file suffixed _impl
...
, are placed in
...
In this way, the parser is represented
by three files
...
h:
// parser
...
h:

expr(), prim(),

and

term(),

implementing the parser is pre-

436

Source Files and Programs

Chapter 15

// parser_impl
...
h"
#include "error
...
h"
using Error::error;
using namespace Lexer;
namespace Parser {
double prim(bool get);
double term(bool get);
double expr(bool get);
}

// interface for implementers

The distinction between the user interface and the interface for implementers would be even clearer
had we used a Parser_impl namespace (§14
...
3)
...
h is #included to give the compiler a chance to check consistency (§15
...
1)
...
cpp together with #include directives
for the headers that the Parser functions need:
// parser
...
h"
#include "table
...
*/ }
double Parser::term(bool get) { /*
...
*/ }

Graphically, the parser and the driver’s use of it look like this:
parser
...
h

error
...
h

parser_impl
...
cpp

parser
...
3
...
To simplify
this structure, we could have #included table
...
h rather than in parser
...
However,
table
...
In fact, it is used by just one function, prim(),

Section 15
...
2

Multiple-Header Organization

437

so if we were really keen on minimizing dependencies we could place prim() in its own
...
h there only:
parser
...
h

error
...
h

parser_impl
...
cpp

prim
...
For realistically sized modules, it is
common to #include extra files where needed for individual functions
...
h, since different subsets of the module’s functions need
different shared contexts
...
h notation is not a standard or even a common convention; it is simply
the way I like to name things
...
h
...
The fundamental reason for
using this type of organization is that it provides a better localization of concerns
...
The multiple-header organization makes it easy to determine exactly what the parser code
depends on and to ignore the rest of the program
...
The simple fact is that maintenance of code is invariably done with incomplete information and from a local perspective
...
The single-header approach – like every other organization centered around a global
repository of information – requires a top-down approach and will forever leave us wondering
exactly what depends on what
...
The effect can be dramatic
...


15
...
2
...
However, those modules are so small that they don’t require their own _impl
...
Such files are needed only where
the implementation of a logical module consists of many functions that need a shared context (in
addition to what is provided to users)
...
h:

438

Source Files and Programs

Chapter 15

// error
...
cpp:
// error
...
h"
int Error::number_of_errors;
double Error::error(const std::string&) { /*
...
h:
#include
#include
namespace Lexer {
enum class Kind : char {/*
...
*/ };
class Token_stream { /*
...
h, the implementation of the lexer depends on error
...
2):
// lexer
...
h"
#include "error
...
h

Lexer::Token_stream is; // defaults to ‘‘read from cin’’
Lexer::Token Lexer::Token_stream::get() { /*
...
*/ };

We could have factored out the #include directive for
considered that excessive for this tiny program
...
h

as the

Lexer’s _impl
...
However, I

Section 15
...
2
...
h – in the module’s implementation to give the compiler a chance to check consistency
...
h:
#include
#include
namespace Table {
extern std::map table;
}

Because we assume that every header may be
declaration of table from its definition:

#included

in several


...
cpp:
#include "table
...
cpp:
// main
...
h"
#include "lexer
...
h"
#include "table
...
*/ }
}
int main(int argc, char∗ argv[]) { /*
...
That way main() calls a driver function placed in a separate source file
...
Then, we cannot rely on code in main() and
must be prepared for the driver to be called from a variety of functions
...
3
...
2 Use of Headers
The number of headers to use for a program is a function of many factors
...
For example, if
your editor/IDE does not make it convenient to look at several files simultaneously, then using
many headers becomes less attractive
...
However, if
you partition the declarations of a large program into the logically minimal-size headers (putting
each structure declaration in its own file, etc
...
I find that excessive
...
In such projects, hundreds of files (not
counting standard headers) are the norm
...
At that scale, the basic techniques discussed here still apply, but their management becomes a Herculean task
...
Remember that for realistically sized programs, the single-header style is not an option
...
The choice between the two styles of organization
occurs (repeatedly) for the parts that make up the program
...
They are complementary techniques that must be considered whenever a significant module is designed and must
be reconsidered as a system evolves
...
It is usually worthwhile to distinguish between the implementers’ interface and the
users’ interface
...
The
expert users’ interfaces (‘‘complete interfaces’’) tend to #include many more features than the average user would ever want to know about
...
The term ‘‘average user’’ is not derogatory
...
In that way, I minimize hassles
...
3
...
Viewed from the program as a whole, many of the declarations needed to make
each logical module complete are redundant
...
2
...

We have two choices
...

The first approach – which led to the final version of the calculator – is tedious and impractical for
realistically sized programs
...

The benefits of an analysis of redundant #includes and the resulting simplifications of the program can be significant both from a logical point of view and by reducing compile times
...
Preferably, it must be applied systematically, since there is no way of knowing how thorough an analysis
a user will find worthwhile
...
3
...
For example:
// error
...

}
#endif

// CALC_ERROR_H

The contents of the file between the #ifndef and #endif are ignored by the compiler if
CALC_ERROR_H is defined
...
h is seen during a compilation, its contents are
read and CALC_ERROR_H is given a value
...
h again during the compilation, the contents are ignored
...
The standard headers all have include guards
...
Consequently, I choose rather long and ugly names for my include
guards
...
Even with C++ implementations that optimize the processing of headers, this can be
undesirable
...
The latter might affect the meaning of the program in unpredictable and
adverse ways
...


15
...
Every function,
object, type, etc
...
3, §15
...
3)
...
2
...
The main computation performed by the
program starts with the invocation of the global function main() and ends with a return from main()
...
*/ }
int main(int argc, char∗ argv[]) { /*
...
In addition, an implementation can
allow other versions of main()
...
2
...

The int returned by main() is passed to whatever system invoked main() as the result of the program
...

This simple story must be elaborated on for programs that contain global variables (§15
...
1) or
that throw an uncaught exception (§13
...
2
...


442

Source Files and Programs

Chapter 15

15
...
1 Initialization of Nonlocal Variables
In principle, a variable defined outside any function (that is, global, namespace, and class static
variables) is initialized before main() is invoked
...
If such a variable has no explicit initializer, it is by default initialized to the default for its type (§17
...
3)
...
For example:
double x = 2;
// nonlocal variables
double y;
double sqx = sqrt(x+y);

Here, x and y are initialized before sqx, so sqrt(2) is called
...

Consequently, it is unwise to create order dependencies between initializers of global variables in
different compilation units
...
5
...
5)
...

Several techniques exist for enforcing an order of initialization of global variables in different
translation units
...
In particular, dynamically linked
libraries do not coexist happily with global variables that have complicated dependencies
...
For example:
int& use_count()
{
static int uc = 0;
return uc;
}

A call use_count() now acts as a global variable except that it is initialized at its first use (§7
...
For
example:
void f()
{
cout << ++use_count(); // read and increment
//
...
The initialization of a local static is
thread-safe (§42
...
3)
...
4), so
that it is done at link time and not subject to data races (§42
...
3)
...

The initialization of nonlocal (statically allocated) variables is controlled by whatever mechanism an implementation uses to start up a C++ program
...
Consequently, one should avoid nonlocal variables that require
run-time initialization in C++ code intended for execution as a fragment of a non-C++ program
...
4) cannot depend on the value of
objects from other translation units and do not require run-time initialization
...


Section 15
...
2

Initialization and Concurrency

443

15
...
2 Initialization and Concurrency
Consider:
int x = 3;
int y = sqrt(++x);

What could be the values of x and y? The obvious answer is ‘‘3 and 2!’’ Why? The initialization of
a statically allocated object with a constant expression is done at link time, so x becomes 3
...
However, the order of initialization of statically allocated objects in a single translation
unit is well defined: they are initialized in definition order (§15
...
1)
...

The flaw in this argument is that if multiple threads are used (§5
...
1, §42
...
No mutual exclusion is implicitly provided to prevent a data race
...
So, the
value of y may be sqrt(4) or sqrt(5)
...

• Avoid dependencies on dynamically initialized objects in other translation units (§15
...
1)
...

[2] Initialize using expressions without side effects
...

[4] Use some form of mutual exclusion (§5
...
4, §42
...


15
...
3 Program Termination
A program can terminate in several ways:
[1] By returning from main()
[2] By calling exit()
[3] By calling abort()
[4] By throwing an uncaught exception
[5] By violating noexcept
[6] By calling quick_exit()
In addition, there are a variety of ill-behaved and implementation-dependent ways of making a program crash (e
...
, dividing a double by zero)
...
4
...
2
...
However, if the program is terminated using
the standard-library function abort(), they are not
...
Calling exit() in a destructor may cause an infinite recursion
...
2
...
Zero indicates successful completion
...
Throwing an exception and catching it ensures that local objects are
properly destroyed (§13
...
1)
...
It is therefore often best to leave
a context by throwing an exception and letting a handler decide what to do next
...
5
...
2)
...
For example:
void my_cleanup();
void somewhere()
{
if (atexit(&my_cleanup)==0) {
// my_cleanup will be called at normal termination
}
else {
// oops: too many atexit functions
}
}

This strongly resembles the automatic invocation of destructors for global variables at program termination (§15
...
1, §16
...
12)
...
A nonzero value
returned by atexit() indicates that the limit is reached
...
Basically, atexit() is a C workaround for the lack of destructors
...
4
...
The destructor of such an object created after a call of
atexit(f) will be invoked before f is invoked
...
You register
functions to be invoked by quick_exit() using at_quick_exit()
...


15
...
1, §15
...
2
...
3
...

Don’t define global entities with the same name and similar-but-different meanings in different translation units; §15
...

Avoid non-inline function definitions in headers; §15
...
2
...
2
...

#include only complete declarations; §15
...
2
...
3
...


Section 15
...
4
...
2
...

Make headers self-contained; §15
...
3
...
3
...

Distinguish between average users’ interfaces and expert users’ interfaces; §15
...
2
...
4
...


This page intentionally left blank

Part III
Abstraction Mechanisms
This part describes C++’s facilities for defining and using new types
...


Chapters
16
17
18
19
20
21
22
23
24
25
26
27
28
29

Classes
Construction, Cleanup, Copy, and Move
Operator Overloading
Special Operators
Derived Classes
Class Hierarchies
Run-Time Type Information
Templates
Generic Programming
Specialization
Instantiation
Templates and Hierarchies
Metaprogramming
A Matrix Design

448

Abstraction Mechanisms

Part III

‘‘
...
For the reformer makes
enemies of all those who profit by the old order, and only lukewarm defenders in all
those who would profit by the new order
...

– Doug McIlroy








Introduction
Class Basics
Member Functions; Default Copying; Access Control; class and struct; Constructors; explicit
Constructors; In-Class Initializers; In-Class Function Definitions; Mutability; Self-Reference; Member Access; static Members; Member Types
Concrete Classes
Member Functions; Helper Functions; Overloaded Operators; The Significance of Concrete
Classes
Advice

16
...

In addition, derived classes (§3
...
4, Chapter 20) and templates (§3
...

A type is a concrete representation of a concept (an idea, a notion, etc
...
, provides a concrete approximation of the mathematical concept of a real number
...
We design a new type to provide
a definition of a concept that has no direct counterpart among the built-in types
...
A program that provides types that
closely match the concepts of the application tends to be easier to understand, easier to reason
about, and easier to modify than a program that does not
...
In addition, it makes many sorts of code analysis feasible
...

The fundamental idea in defining a new type is to separate the incidental details of the implementation (e
...
, the layout of the data used to store an object of the type) from the properties essential to the correct use of it (e
...
, the complete list of functions that can access the data)
...

This chapter focuses on relatively simple ‘‘concrete’’ user-defined types that logically don’t differ much from built-in types:
§16
...

§16
...

The following chapters go into greater detail and presents abstract classes and class hierarchies:
Chapter 17 Construction, Cleanup, Copy, and Move presents the variety of ways to control
initialization of objects of a class, how to copy and move objects, and how to
provide ‘‘cleanup actions’’ to be performed when an object is destroyed (e
...
,
goes out of scope)
...

Chapter 19 Special Operators considers how to define and use operators (such as [], (), −>,
new) that are ‘‘special’’ in that they are commonly used in ways that differ from
arithmetic and logical operators
...

Chapter 20 Derived Classes introduces the basic language features supporting object-oriented programming
...

Chapter 21 Class Hierarchies focuses on the use of base and derived classes to effectively
organize code around the notion of class hierarchies
...

Chapter 22 Run-Time Type Information describes the techniques for explicitly navigating
class hierarchies
...


16
...

• A class consists of a set of members
...

• Member functions can define the meaning of initialization (creation), copy, move, and
cleanup (destruction)
...
2

Class Basics

451






Members are accessed using
...

Operators, such as +, !, and [], can be defined for a class
...

The public members provide the class’s interface and the private members provide implementation details
...

For example:
class X {
private:
int m;
public:
X(int i =0) :m{i} { }
int mf(int i)
{
int old = m;
m = i;
return old;
}

// the representation (implementation) is private
// the user interface is public
// a constructor (initialize the data member m)
// a member function

// set a new value
// return the old value

};
X var {7}; // a variable of type X, initialized to 7
int user(X var, X∗ ptr)
{
int x = var
...
m;
}

// access using
...
The style is tutorial: a gradual development of ideas, with details postponed until later
...
2
...
3
...
2) to define the representation of a Date and a set of functions for manipulating variables of this type:
struct Date {
int d, m, y;
};

// representation

void init_date(Date& d, int, int, int);
void add_year(Date& d, int n);
void add_month(Date& d, int n);
void add_day(Date& d, int n);

// initialize d
// add n years to d
// add n months to d
// add n days to d

There is no explicit connection between the data type, Date, and these functions
...
2
...
2)
...
init(16,10,1996);
my_birthday
...
add_day(1);
//
...
In that
case, the name refers to that member of the object for which the function was invoked
...
m
...
m
...
But see §16
...
12 for the notion of a static member
...
2
...
In particular, a class object can be initialized with a copy of an
object of its class
...
2
...
If that default is not the behavior
wanted for a class X, a more appropriate behavior can be provided (§3
...
5)
...
For example:
void f(Date& d)
{
d = my_birthday;
}

Again, the default semantics is memberwise copy
...
3, §17
...


16
...
3 Access Control
The declaration of Date in the previous subsection provides a set of functions for manipulating a
Date
...
This restriction
can be expressed by using a class instead of a struct:
class Date {
int d, m, y;
public:
void init(int dd, int mm, int yy);
void add_year(int n);
void add_month(int n);
void add_day(int n);

// initialize
// add n years
// add n months
// add n days

};

The public label separates the class body into two parts
...
The second, public, part constitutes the public interface to objects
of the class
...
2
...
For example:
void Date::add_year(int n)
{
y += n;
}

However, nonmember functions are barred from using private members
...
y −= 200;
// error: Date::y is private
}

The init() function is now essential because making the data private forces us to provide a way of
initializing members
...
m = 3;
dx
...
For example, any error causing a Date to take on an illegal value (for
example, December 36, 2016) must be caused by code in a member function
...
This is a special case of the general observation that any change to the behavior of the type Date can and must
be effected by changes to its members
...
User code
directly depends only on the public interface and need not be rewritten (although it may need to be
recompiled)
...
A more subtle, but most significant, advantage is
that focusing on the design of a good interface simply leads to better code because thoughts and
time otherwise devoted to debugging are expended on concerns related to proper use
...
It can
therefore be circumvented by address manipulation (§7
...
1) and explicit type conversion (§11
...

But this, of course, is cheating
...
Only hardware can offer perfect protection against malicious use of a general-purpose language, and even that is hard to do in realistic systems
...
2
...
};

is called a class definition; it defines a type called X
...
Also, like declarations that are not definitions, a class definition can be replicated in different source files using #include without violating the one-definition
rule (§15
...
3)
...
*/ };

is simply shorthand for
class S { public: /*
...

Which style you use depends on circumstances and taste
...
’’ If I think of a class as ‘‘a proper type with an invariant,’’ I use
class
...
4
...
2, §13
...

By default, members of a class are private:
class Date1 {
int d, m, y;
// private by default
public:
Date1(int dd, int mm, int yy);
void add_year(int n);
// add n years
};

Section 16
...
4

class

and struct

455

However, we can also use the access specifier private: to say that the members following are private,
just as public: says that the members following are public:
struct Date2 {
private:
int d, m, y;
public:
Date2(int dd, int mm, int yy);
void add_year(int n);
// add n years
};

Except for the different name, Date1 and Date2 are equivalent
...
In fact, it often makes sense to place data
members last to emphasize the functions providing the public user interface
...

Access specifiers can be used many times in a single class declaration
...
5)
...
However, allowing many
access specifiers in a class is useful for machine-generated code
...
2
...
Because it is nowhere stated that an object must be initialized, a programmer can forget to
do so – or do so twice (often with equally disastrous results)
...
Because such a
function constructs values of a given type, it is called a constructor
...
For example:

456

Classes

Chapter 16

class Date {
int d, m, y;
public:
Date(int dd, int mm, int yy);
//
...
If
the constructor requires arguments, these arguments must be supplied:
Date today = Date(23,6,1983);
Date xmas(25,12,1990);
// abbreviated form
Date my_birthday;
// error : initializer missing
Date release1_0(10,12);
// error : third argument missing

Since a constructor defines initialization for a class, we can use the {}-initializer notation:
Date today = Date {23,6,1983};
Date xmas {25,12,1990};
// abbreviated form
Date release1_0 {10,12};
// error : third argument missing

I recommend the {} notation over the () notation for initialization because it is explicit about what is
being done (initialization), avoids some potential mistakes, and can be used consistently (§2
...
2,
§6
...
5)
...
4
...
3
...
1), but they are rare
...
For example:
class Date {
int d, m, y;
public:
//
...
3)
...
m, today
...
y
// default initialized as today
// default initialized as today

The proliferation of constructors in the Date example is typical
...
It takes more
thought to carefully decide what features are really needed and to include only those
...
One way of

Section 16
...
5

Constructors

457

reducing the number of related functions is to use default arguments (§12
...
5)
...
’’
class Date {
int d, m, y;
public:
Date(int dd =0, int mm =0, int yy =0);
//
...
d;
m = mm ? mm : today
...
y;
// check that the Date is valid
}

When an argument value is used to indicate ‘‘pick the default,’’ the value chosen must be outside
the set of possible values for the argument
...
Fortunately, there is no year zero on the European calendar; 1AD
(year==1) comes immediately after 1BC (year==−1)
...
d, int mm =today
...
y);
//
...
That way, we have
the option to later improve the implementation of the default
...
Given constructors, other member functions no longer have
to deal with the possibility of uninitialized data (§16
...
1)
...
2
...
For example:
complex d {1};

// d=={1,0} (§5
...
2)

458

Classes

Chapter 16

Such implicit conversions can be extremely useful
...
That’s exactly what mathematics
requires
...
Consider Date:
void my_fct(Date d);
void f()
{
Date d {15};
//
...

}

// plausible: x becomes {15,today
...
y}
// obscure
// obscure

At best, this is obscure
...

Fortunately, we can specify that a constructor is not used as an implicit conversion
...

For example:
class Date {
int d, m, y;
public:
explicit Date(int dd =0, int mm =0, int yy =0);
//
...

}

// error: argument passing does not do implicit conversions
// error: argument passing does not do implicit conversions
// OK: explicit

An initialization with an = is considered a copy initialization
...
However, such a copy may be optimized away (elided), and a
move operation (§3
...
2, §17
...
2) may be used if the initializer is an rvalue (§6
...
1)
...
Explicit initialization is known as direct initialization
...
You need a
good reason not to do so (as for complex)
...


Section 16
...
6

explicit

Constructors

459

If a constructor is declared explicit and defined outside the class, that explicit cannot be repeated:
class Date {
int d, m, y;
public:
explicit Date(int dd);
//
...
*/ }
explicit Date::Date(int dd) { /*
...
However, explicit
can also be useful for constructors with zero or more than one argument
...
3
...
3)
...
2
...
For example:
class Date {
int d, m, y;
public:
Date(int, int, int);
Date(int, int);
Date(int);
Date();
Date(const char∗);
//
...
2
...
Alternatively, we can add initializers to data members:
class Date {
int d {today
...
m};
int y {today
...


// day, month, year
// day, month, today’s year
// day, today’s month and year
// default Date: today
// date in string representation

Now, each constructor has the d, m, and y initialized unless it does it itself
...
m}, y{today
...
2
...
1
...
That is, in-class definition of member functions is for
small, rarely modified, frequently used functions
...
Like the class
itself, the member function’s meaning must be the same wherever it is #included (§15
...
3)
...
3
...
Consider:
class Date {
public:
void add_month(int n) { m+=n; }
//
...
I could equivalently have
written:

Section 16
...
8

In-Class Function Definitions

class Date {
public:
void add_month(int n) { m+=n; }
//
...
It also provides a
textual separation of a class’s interface and implementation
...
3
...


16
...
9 Mutability
We can define a named object as a constant or as a variable
...
Since the precise terminology can be a bit
clumsy, we end up referring to some variables as being constant or briefer still to const variables
...
Systematic use of immutable objects leads to more comprehensible
code, to more errors being found early, and sometimes to improved performance
...
3, Chapter 41)
...
For freestanding functions that
means functions that take const T& arguments
...


16
...
9
...
Unfortunately, we
didn’t provide a way of examining the value of a Date
...

};

// add n years

462

Classes

Chapter 16

The const after the (empty) argument list in the function declarations indicates that these functions
do not modify the state of a Date
...
For example:
int Date::year() const
{
return ++y;
// error: attempt to change member value in const function
}

When a const member function is defined outside its class, the const suffix is required:
int Date::year()
{
return y;
}

// error: const missing in member function type

In other words, const is part of the type of Date::day(), Date::month(), and Date::year()
...
For example:
void f(Date& d, const Date& cd)
{
int i = d
...
add_year(1);
// OK
int j = cd
...
add_year(1);

// OK
// error: cannot change value of a const Date

}

16
...
9
...
That is, to a user, the function appears not to change the state of its object, but some detail that
the user cannot directly observe is updated
...
For example,
the Date class might have a function returning a string representation
...
Therefore, it would make sense to keep a copy so
that repeated requests would simply return the copy, unless the Date’s value had been changed
...

string string_rep() const;
// string representation
private:
bool cache_valid;
string cache;
void compute_cache_value(); // fill cache
//
...
2
...
2

Physical and Logical Constness

463

From a user’s point of view, string_rep doesn’t change the state of its Date, so it clearly should be a
const member function
...

Such problems could be solved through brute force using a cast, for example, a const_cast
(§11
...
2)
...


16
...
9
...

string string_rep() const;
private:
mutable bool cache_valid;
mutable string cache;
void compute_cache_value() const;
//
...
For example:
void f(Date d, const Date cd)
{
string s1 = d
...
string_rep();
//
...
2
...
4 Mutability through Indirection
Declaring a member mutable is most appropriate when only a small part of a representation of a
small object is allowed to change
...
If that technique is used, the stringwith-cache example becomes:

464

Classes

Chapter 16

struct cache {
bool valid;
string rep;
};
class Date {
public:
//
...

};

// string representation
// initialize in constructor
// fill what cache refers to

string Date::string_rep() const
{
if (!c−>valid) {
compute_cache_value();
c−>valid = true;
}
return c−>rep;
}

The programming techniques that support a cache generalize to various forms of lazy evaluation
...

The human reader may consider such an object as ‘‘a kind of subobject,’’ but the compiler does not
know such pointers or references to be any different from any others
...


16
...
10 Self-Reference
The state update functions add_year(), add_month(), and add_day() (§16
...
3) were defined not to
return values
...
For example, we would like to write:
void f(Date& d)
{
//
...
add_day(1)
...
add_year(1);
//
...
To do this, each function must be declared to return a reference to a Date:
class Date {
//
...
2
...
For example:
Date& Date::add_year(int n)
{
if (d==29 && m==2 && !leapyear(y+n)) { // beware of February 29
d = 1;
m = 3;
}
y += n;
return ∗this;
}

The expression ∗this refers to the object for which a member function is invoked
...
In a non-const member function of class X, the type of this is X∗
...
In a
const member function of class X, the type of this is const X∗ to prevent modification of the object
itself (see also §7
...

Most uses of this are implicit
...
For example,
the add_year function could equivalently, but tediously, have been defined like this:
Date& Date::add_year(int n)
{
if (this−>d==29 && this−>m==2 && !leapyear(this−>y+n)) {
this−>d = 1;
this−>m = 3;
}
this−>y += n;
return ∗this;
}

One common explicit use of this is in linked-list manipulation
...

};

Explicit use of this is required for access to members of base classes from a derived class that is a
template (§26
...
7)
...
2
...
(dot) operator to an object of class X or by
applying the −> (arrow) operator to a pointer to an object of class X
...
m = 1;
// OK
x−>m = 1;
// error: x is not a pointer
px−>m = 1;
// OK
px
...
However, a programmer might be confused, so from the first days of C the rule has been to use separate operators
...
For example:
void X::f()
{
m = 1;
}

// OK: ‘‘this->m = 1;’’ (§16
...
10)

That is, an unqualified member name acts as if it had been prefixed by this−>
...
For example:

Section 16
...
11

Member Access

467

struct S {
int m;
int f();
static int sm;
};
int X::f() { return m; }
int X::sm {7};
int (S::∗) pmf() {&S::f};

// X’s f
// X’s static member sm (§16
...
12)
// X’s member f

That last construct (a pointer to member) is fairly rare and esoteric; see §20
...
I mention it here just
to emphasize the generality of the rule for ::
...
2
...

Our Date class became dependent on the global variable today
...
This is the kind of
constraint that causes a class to be useless outside the context in which it was first written
...
Maybe ‘‘just one little global variable’’ isn’t too unmanageable, but that style
leads to code that is useless except to its original programmer
...

Fortunately, we can get the convenience without the encumbrance of a publicly accessible
global variable
...
There is exactly one copy of a static member instead of one copy per object, as for
ordinary non-static members (§6
...
2)
...

Here is a redesign that preserves the semantics of default constructor values for Date without the
problems stemming from reliance on a global:
class Date {
int d, m, y;
static Date default_date;
public:
Date(int dd =0, int mm =0, int yy =0);
//
...
d;
m = mm ? mm : default_date
...
y;
//
...

}

468

Classes

Chapter 16

Using set_default(), we can change the default date when appropriate
...
In addition, a static member can be referred to without mentioning an object
...
For example:
void f()
{
Date::set_default(4,5,1945);
}

// call Date’s static member set_default()

If used, a static member – a function or data member – must be defined somewhere
...
For example:
Date Date::default_date {16,12,1770};

// definition of Date::default_date

void Date::set_default(int d, int m, int y)
{
default_date = {d,m,y};
}

// definition of Date::set_default
// assign new value to default_date

Now, the default value is Beethoven’s birth date – until someone decides otherwise
...
For example:
Date copy_of_default_date = Date{};
void f(Date);
void g()
{
f(Date{});
}

Consequently, we don’t need a separate function for reading the default date
...
For example:
void f1(Date);
void f2(Date);
void f2(int);
void g()
{
f1({});
f2({}):
f2(Date{});

// OK: equivalent to f1(Date{})
// error: ambiguous: f2(int) or f2(Date)?
// OK

In multi-threaded code, static data members require some kind of locking or access discipline to
avoid race conditions (§5
...
4, §41
...
4)
...
Older code tends to use static
members in ways that imply race conditions
...
2
...
2
...
For example:
template
class Tree {
using value_type = T;
enum Policy { rb, splay, treeps };
class Node {
Node∗ right;
Node∗ left;
value_type value;
public:
void f(Tree∗);
};
Node∗ top;
public:
void g(const T&);
//
...
It can only refer to non-static members when it is given an object of the enclosing class to
refer to
...

A nested class has access to members of its enclosing class, even to private members (just as a
member function has), but has no notion of a current object of the enclosing class
...
For example:
template
void Tree::g(Tree::Node∗ p)
{
value_type val = right−>value;
value_type v = p−>right−>value;
p−>f(this);
}

// error : no object of type Tree::Node
// error : Node::right is private
// OK

Member classes are more a notational convenience than a feature of fundamental importance
...
2
...
1
...
Member enums are often an alternative to enum classes
when it comes to avoiding polluting an enclosing scope with the names of enumerators (§8
...
1)
...
3 Concrete Classes
The previous section discussed bits and pieces of the design of a Date class in the context of introducing the basic language features for defining classes
...

Small, heavily used abstractions are common in many applications
...
Every application uses several of these
...
A typical
application uses a few directly and many more indirectly from libraries
...
However, most are not, and
cannot be, directly supported by the language because there are too many of them
...
Consequently, mechanisms must be provided for the user to define small concrete
types
...
4) and classes in class hierarchies (§20
...
2)
...
This
distinguishes it from abstract classes (§3
...
2, §20
...
Having the representation available allows us:
• To place objects on the stack, in statically allocated memory, and in other objects
• To copy and move objects (§3
...
5)
• To refer directly to named objects (as opposed to accessing through pointers and references)
This makes concrete classes simple to reason about and easy for the compiler to generate optimal
code for
...
6
...
2
...
4)
...
They are a foundation of elegant programming
...
In this light,
let us build a better Date class:
namespace Chrono {
enum class Month { jan=1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };
class Date {
public:
// public interface:
class Bad_date { }; // exception class
explicit Date(int dd ={}, Month mm ={}, int yy ={});

// {} means ‘‘pick a default’’

Section 16
...
2
...

[2] A set of functions allowing a user to examine a Date
...

[3] A set of functions allowing the user to modify Dates without actually having to know the
details of the representation or fiddle with the intricacies of the semantics
...
2
...

[5] A class, Bad_date, to be used for reporting errors as exceptions
...
The helper functions are not members and have no
direct access to the representation of a Date, but they are identified as related by the use of
the namespace Chrono
...

I considered introducing separate types Day and Year to cope with possible confusion of
Date{1995,Month::jul,27} and Date{27,Month::jul,1995}
...
Almost all such errors are caught at run time anyway – the 26th of July year 27

472

Classes

Chapter 16

is not a common date in my work
...
Furthermore, the day of the month can’t be properly checked in
isolation from its month and year
...
Note that for Month the {} gives the
(default) value 0 just as for integers even though it is not a valid Month (§8
...
However, in this
case, that’s exactly what we want: an otherwise illegal value to represent ‘‘pick the default
...
g
...
For some types,
there is a conventional default (e
...
, 0 for integers); for others, no default makes sense; and finally,
there are some types (such as Date) where the question of whether to provide a default is nontrivial
...
I provide one for Date
primarily to be able to discuss how to do so
...
2
...
If needed, it
can be added as an implementation detail without affecting the user interface
...
year()};
if (d
...
month()==Month::feb) {
//
...
add_day(1);
cout << "day after:" << d+1 << '\n';
Date dd; // initialized to the default date
cin>>dd;
if (dd==d) cout << "Hurray!\n";
}

This assumes that the addition operator, +, has been declared for Dates
...
3
...

Note the use of explicit qualification of dec and feb by Month
...
4
...

Why is it worthwhile to define a specific type for something as simple as a date? After all, we
could just define a simple data structure:
struct Date {
int day, month, year;
};

Each programmer could then decide what to do with it
...
In effect, the notion of a date would be scattered throughout the system, which would make it
hard to understand, document, or change
...
3

Concrete Classes

473

causes extra work for every user of the structure
...
For example,
incrementing a Date must deal with leap years, with the fact that months are of different lengths,
and so on
...
If we
decided to change it, we would need to modify only a designated set of functions
...

To simplify, I decided to eliminate the notion of changing the default date
...
3
...
I seriously considered eliminating the notion of a default date altogether
...
However, that can be inconvenient
and surprising, and more importantly common interfaces used for generic code require default construction (§17
...
3)
...
I
chose January 1, 1970, because that is the starting point for the C and C++ standard-library time
routines (§35
...
6)
...
However, design – including class design – is about making decisions, rather than just deciding to postpone them or to leave all options open for users
...


16
...
1 Member Functions
Naturally, an implementation for each member function must be provided somewhere
...
year();
if (m == Month{}) m = default_date()
...
day();
if (!is_valid()) throw Bad_date();
}

The constructor checks that the data supplied denotes a valid Date
...
4
...
1, Chapter 13), which indicates that something
went wrong
...
Initialization is a
relatively complicated operation because it involves data validation
...
On the
other hand, once a Date has been created, it can be used and copied without further checking
...
Other member functions can rely on that invariant and must maintain it
...
4
...
2, §13
...

I’m using the value Month{} – which doesn’t represent a month and has the integer value 0 – to
represent ‘‘pick the default month
...
But I decided that it was better to use an obviously anomalous value to represent
‘‘pick the default month’’ rather than give the appearance that there were 13 months in a year
...
4)
...
4) to initialize the members
...
This clearly does not provide optimal performance in the (hopefully rare) case of an error, but the use of member initializers leaves the structure of the code obvious
...
Had I aimed at
optimal performance, I would have used three separate constructors rather than a single constructor
with default arguments
...
However, I found the resulting
user code more complicated and less robust than code relying on catching the exception:
void fill(vector& aa)
{
while (cin) {
Date d;
try {
cin >> d;
}
catch (Date::Bad_date) {
//
...

continue;
}
aa
...
4
...

For example, is_valid() might reject dates from before the modern calendar became commonly used
...
For example:
inline int Date::day() const
{
return d;
}

Section 16
...
1

Member Functions

475

Date& Date::add_month(int n)
{
if (n==0) return ∗this;
if (n>0) {
int delta_y = n/12;
int mm = static_cast(m)+n%12;
if (12 < mm) {
++delta_y;
mm −= 12;
}

// number of whole years
// number of months ahead
// note: dec is represented by 12

//
...

y += delta_y;
m = static_cast(mm);
return ∗this;
}
//
...

return ∗this;
}

I wouldn’t call the code for add_month() pretty
...
This points to a problem: adding a
month is conceptually simple, so why is our code getting complicated? In this case, the reason is
that the d,m,y representation isn’t as convenient for the computer as it is for us
...
g
...
That would make computation on Dates simple at the expense of complexity in providing output fit for humans
...
2
...
Also, Date
doesn’t need a destructor because a Date owns no resources and requires no cleanup when it goes
out of scope (§3
...
1
...


16
...
2 Helper Functions
Typically, a class has a number of functions associated with it that need not be defined in the class
itself because they don’t need direct access to the representation
...

How are such functions ‘‘associated’’ with class Date? In early C++, as in C, their declarations
were simply placed in the same file as the declaration of class Date
...
2
...
For example:
#include "Date
...
3
...
*/};
int diff(Date a, Date b);
bool is_leapyear(int y);
bool is_date(int d, Month m, int y);
const Date& default_date();
Date next_weekday(Date d);
Date next_saturday(Date d);
//
...
Using a namespace to hold a single class is usually an overelaboration
that leads to inconvenience
...
3
...
A Month shouldn’t be outside the jan to dec range, but it
is possible (someone might have been sloppy with a cast), so I check
...
3
...
For example,
defines the equality operator, ==, to work for Dates:

operator==()

inline bool operator==(Date a, Date b)
// equality
{
return a
...
day() && a
...
month() && a
...
year();
}

Other obvious candidates are:
bool operator!=(Date, Date);
bool operator<(Date, Date);
bool operator>(Date, Date);
//
...
add_day(1); }
Date& operator−−(Date& d) { return d
...
add_day(n); }
Date& operator−=(Date& d, int n) { return d
...
2
...

For Date, these operators can be seen as mere conveniences
...
3), vectors (§4
...
1), and function-like objects (§3
...
3, §19
...
2) – the use of
conventional operators is so firmly entrenched in people’s minds that their definition is almost
mandatory
...

For Date, I was tempted to provide += and −= as member functions instead of add_day()
...
2
...
1)
...
3, §17
...
3)
...
3
...
2
...
4), and also to emphasize their similarity to built-in types
such as int and char
...
Concrete types have also
been called value types and their use value-oriented programming
...
2
...

The intent of a concrete type is to do a single, relatively simple thing well and efficiently
...
In
particular, concrete types are not intended to display run-time polymorphic behavior (see §3
...
3,
§20
...
2)
...

If you want to ‘‘reuse’’ a concrete type, you use it in the implementation of your new type exactly
as you would have used an int
...

};

Alternatively, the derived class mechanism discussed in Chapter 20 can be used to define new types
from a concrete class by describing the desired differences
...
4
...
2) is an example of this
...
5
...
4, Chapter 22)
...
In particular, no indirection through pointers is necessary for access to objects of
concrete classes, and no ‘‘housekeeping’’ data is stored in objects of concrete classes
...
The layout of an object is known at compile time so that inlining
of operations is trivially achieved
...

A good set of such types can provide a foundation for applications
...
For example:
Month do_something(Date d);

This is far less likely to be misunderstood or misused than:
int do_something(int d);

Lack of concrete types can lead to obscure programs and time wasted when each programmer
writes code to directly manipulate ‘‘simple and frequently used’’ data structures represented as

Section 16
...
4

The Significance of Concrete Classes

479

simple aggregates of built-in types
...


16
...
1
...
1
...
2
...

[4] Define a constructor to handle initialization of objects; §16
...
5
...
2
...

[6] Declare a member function that does not modify the state of its object const; §16
...
9
...
Where applicable, prefer a concrete type over
more complicated classes and over plain data structures; §16
...

[8] Make a function a member only if it needs direct access to the representation of a class;
§16
...
2
...
3
...

[10] Make a member function that doesn’t modify the value of its object a const member function;
§16
...
9
...

[11] Make a function that needs access to the representation of a class but needn’t be called for a
specific object a static member function; §16
...
12
...

– Charles Darwin












Introduction
Constructors and Destructors
Constructors and Invariants; Destructors and Resources; Base and Member Destructors;
Calling Constructors and Destructors; virtual Destructors
Class Object Initialization
Initialization Without Constructors; Initialization Using Constructors; Default Constructors;
Initializer-List Constructors
Member and Base Initialization
Member Initialization; Base Initializers; Delegating Constructors; In-Class Initializers; static
Member Initialization
Copy and Move
Copy; Move
Generating Default Operations
Explicit Defaults; Default Operations; Using Default Operations; deleted Functions
Advice

17
...

// copy s1 into ident()
// move the result of ident(s1) into s1;
// s1’s value is "Adams"
...


}

Clearly, after the call of ident(), the value of s1 ought to be "Adams"
...
Next,
we construct s2 with the value "Prachett" and copy it into s1
...
The difference between move and copy is that after a copy two
objects must have the same value, whereas after a move the source of the move is not required to
have its original value
...
They are
particularly useful for implementing the notion of moving a resource (§3
...
1
...
2)
...
For example, in this simple example the temporary
variable is typically eliminated
...

Constructors, copy and move assignment operations, and destructors directly support a view of
lifetime and resource management
...
The interaction between object lifetime and errors is explored further in §13
...
3
...

Construction of objects plays a key role in many designs
...

Constructors, destructors, and copy and move operations for a type are not logically separate
...
If a class X has a
destructor that performs a nontrivial task, such as free-store deallocation or lock release, the class is
likely to need the full complement of functions:

Section 17
...

};

Introduction

483

// ‘‘ordinar y constructor’’: create an object
// default constructor
// copy constructor
// move constructor
// copy assignment: clean up target and copy
// move assignment: clean up target and move
// destructor: clean up

There are five situations in which an object is copied or moved:
• As the source of an assignment
• As an object initializer
• As a function argument
• As a function return value
• As an exception
In all cases, the copy or move constructor will be applied (unless it can be optimized away)
...
4
...
5)
...
6
...
Those are necessary for a full understanding, but
most people just learn the general rules from examples
...
2 Constructors and Destructors
We can specify how an object of a class is to be initialized by defining a constructor (§16
...
5,
§17
...
To complement constructors, we can define a destructor to ensure ‘‘cleanup’’ at the point of
destruction of an object (e
...
, when it goes out of scope)
...
So do other techniques relying
on a pair of actions, such as do/undo, start/stop, before/after, etc
...
2
...
1
//
...
2
...
For example:
class Vector {
public:
Vector(int s);
//
...
The name of a class cannot be used for an ordinary member function, data member, member
type, etc
...
For example:
struct S {
S();
void S(int);
int S;
enum S { foo, bar };
};

// fine
// error : no type can be specified for a constructor
// error : the class name must denote a constructor
// error : the class name must denote a constructor

A constructor’s job is to initialize an object of its class
...
Consider:
class Vector {
public:
Vector(int s);
//
...
’’ The constructor must make that true
...
2
...
If the constructor cannot establish the invariant, no object is created and the constructor must ensure that no
resources are leaked (§5
...
3)
...
Examples of resources
are memory (§3
...
1
...
3
...
3), and thread handles (§5
...
1)
...
4
...
2)
• To clarify the behavior of the class (e
...
, under error conditions; §13
...
4
...
2, §16
...
1)
• To clarify the class’s management of resources (§13
...


17
...
2 Destructors and Resources
A constructor initializes an object
...
Sometimes, creating that environment involves acquiring a resource – such as a
file, a lock, or some memory – that must be released after use (§5
...
3)
...
Inevitably, such a
function is called a destructor
...
One meaning of ˜ is ‘‘complement’’ (§11
...
2), and a destructor for a class complements its constructors
...
Destructors are called implicitly when an automatic variable goes out of scope, an object
on the free store is deleted, etc
...
2
...

Destructors typically clean up and release resources
...

private:
double∗ elem; // elem points to an array of sz doubles
int sz;
// sz is non-negative
};

For example:

// constructor: acquire memory
// destructor: release memory

486

Construction, Cleanup, Copy, and Move

Chapter 17

Vector∗ f(int s)
{
Vector v1(s);
//
...

delete p;
}

Here, the Vector v1 is destroyed upon exit from f()
...
In both cases, Vector’s destructor is invoked to free
(deallocate) the memory allocated by the constructor
...
In
that case, an exception std::bad_alloc (§11
...
3) is thrown by new and the exception-handling mechanism invokes the appropriate destructors so that all memory that has been acquired (and only that)
is freed (§13
...
1)
...
2, §13
...

A matching constructor/destructor pair is the usual mechanism for implementing the notion of a
variably sized object in C++
...

A type that has no destructor declared, such as a built-in type, is considered to have a destructor
that does nothing
...
6)
...
2
...
2
...
A constructor builds a class object ‘‘from the bottom up’’:
[1] first, the constructor invokes its base class constructors,
[2] then, it invokes the member constructors, and
[3] finally, it executes its own body
...

In particular, a virtual base is constructed before any base that might use it and destroyed after all
such bases (§21
...
5
...
This ordering ensures that a base or a member is not used before it has
been initialized or used after it has been destroyed
...
2
...
Doing so violates language rules and the results are usually disastrous
...
See also §17
...

If a class is used so that a default constructor is needed, and if the class does not have other constructors, the compiler will try to generate a default constructor
...
s is initialized to ""

Similarly, memberwise initialization can be used if initializers are needed
...
x is initialized with 1

See also §17
...
1
...
2
...
It is typically not only
unnecessary to explicitly call a destructor; doing so would lead to nasty errors
...
Consider a container that
(like std::vector) maintains a pool of memory into which it can grow and shrink (e
...
, using
push_back() and pop_back())
...

new(p) X{a}; // copy construct an X with the value a in address p
//
...
2
...

Conversely, when we remove an element, the container needs to invoke its destructor:
void C::pop_back()
{
//
...
That notation should never be used for an object
that is destroyed in the normal way (by its object going out of scope or being deleted)
...
6
...

If declared for a class X, a destructor will be implicitly invoked whenever an X goes out of scope
or is deleted
...
6
...

Of the two alternatives, using private is the more flexible
...

void destroy() { this−>˜Nonlocal(); }
private:
//
...

delete p;
p
...
2
...

For example:
class Shape {
public:
//
...

void draw();
˜Circle();
//
...
2
...

delete p;
// invoke the appropriate destructor
};

Had Shape’s destructor not been virtual that delete would have failed to invoke the appropriate
derived class destructor (e
...
, ˜Circle())
...


17
...
It also
shows how to define constructors to accept arbitrarily sized homogeneous initializer lists (such as
{1,2,3} and {1,2,3,4,5,6})
...
3
...
For example:
int a {1};
char∗ p {nullptr};

Similarly, we can initialize objects of a class for which we have not defined a constructor using
• memberwise initialization,
• copy initialization, or
• default initialization (without an initializer or with an empty initializer list)
...
9 in D minor, Op
...

The default initialization of using {} is defined as initialization of each member by {}
...
3
...


490

Construction, Cleanup, Copy, and Move

Chapter 17

Where no constructor requiring arguments is declared, it is also possible to leave out the initializer completely
...

}

For this, the rules are not as clean as we might like
...
4
...
However, for local variables
and free-store objects, the default initialization is done only for members of class type, and members of built-in type are left uninitialized, so the value of beta is {"","",unknown}
...
For example:
struct Buf {
int count;
char buf[16∗1024];
};

You can use a Buf as a local variable without initializing it before using it as a target for an input
operation
...
If you want guaranteed initialization or simply dislike surprises, supply an initializer, such as {}
...

}

Naturally, memberwise initialization works only if we can access the members
...

};
Checked_pointer p {new int{7}};

// error : can’t access p
...


Section 17
...
2

Initialization Using Constructors

491

17
...
2 Initialization Using Constructors
Where memberwise copy is not sufficient or desirable, a constructor can be defined to initialize an
object
...
2
...

If a constructor is declared for a class, some constructor will be used for every object
...
For
example:
struct X {
X(int);
};
X x0;
X x1 {};
X x2 {2};
X x3 {"two"};
X x4 {1,2};
X x5 {x4};

// error : no initializer
// error : empty initializer
// OK
// error: wrong initializer type
// error: wrong number of initializers
// OK: a copy constructor is implicitly defined (§17
...
3
...
However, the copy constructor
does not disappear (§17
...
3); the assumption is that an object can be copied (once properly constructed)
...
3
...
6
...

I used the {} notation to make explicit the fact that I am initializing
...
The {} notation for initialization can be used to
provide arguments to a constructor wherever an object can be constructed
...
4)
// initialize base and member

// initialize global variable

void f(int a)
{
X def {};
Y de2 {};
X∗ p {nullptr};
X var {2};
p = new X{4};
X a[] {1,2,3};
vector v {1,2,3,4};
}

// error : no default value for X
// OK: use default constructor
// initialize local variable
// initialize object on free store
// initialize array elements
// initialize vector elements

492

Construction, Cleanup, Copy, and Move

Chapter 17

For this reason, {} initialization is sometimes referred to as universal initialization: the notation can
be used everywhere
...

The = and () notations for initialization (§6
...
5) are not universal
...
If you insist on using = or () initialization, you have to remember where they are
allowed and what they mean
...
3) apply for constructors
...
0}};
S s3 {nullptr};

// S::S(const char*)
// S::S(double*);
// ambiguous: S::S(const char*) or S::S(double*)?

Note that the {}-initializer notation does not allow narrowing (§2
...
2)
...


17
...
2
...
That is, you can
ensure that for a class, you will get initialization by constructor and not get the memberwise initialization or initializer-list initialization (§17
...
4) that the {} notation also offers
...
3
...
1

Initialization by Constructors

struct S2 {
int a,b;
S2(int a = 0, int b = 0) : a(aa), b(bb) {}
};

493

// constructor

S1 x11(1,2);
S1 x12 {1,2};

// error : no constructor
// OK: memberwise initialization

S1 x13(1);
S1 x14 {1};

// error : no constructor
// OK: x14
...
Consequently, the () and = may be more familiar to you
...
For example:
vector v1 {77};
vector v2(77);

// one element with the value 77
// 77 elements with the default value 0

This problem – and the need to choose – can occur when a type with an initializer-list constructor
(§17
...
4), typically a container, also has an ‘‘ordinary constructor’’ accepting arguments of the element type
...
size()==0)
// empty vector (v7
...


17
...
3 Default Constructors
A constructor that can be invoked without an argument is called a default constructor
...
For example:

494

Construction, Cleanup, Copy, and Move

Chapter 17

class Vector {
public:
Vector(); // default constructor: no elements
//
...
2
...
For example:
class String {
public:
String(const char∗ p = "");
//
...
3
...
3
...

The built-in types are considered to have default and copy constructors
...
3)
...
0 for floating-point types, and nullptr for pointers
...
0
// p becomes nullptr

int∗ p1 = new int;
// uninitialized int
int∗ p2 = new int{}; // the int is initialized to 0
}

Constructors for built-in types are most often used for template arguments
...

};
Handle px;

// will generate int{}

Section 17
...
3

Default Constructors

495

The generated int will be initialized to 0
...
7, §7
...
Therefore, a class containing such members cannot be default constructed unless the programmer supplies in-class member initializers
(§17
...
4) or defines a default constructor that initializes them (§17
...
1)
...
In such cases, a default constructor is obviously required for a class
used as the element type of a vector or array
...
’’ However, a better question is ‘‘For what types does it
make sense to have a default value?’’ or even ‘‘Does this type have a ‘special’ value we can ‘naturally’ use as a default?’’ String has the empty string, "", containers have the empty set, {}, and
numeric values have zero
...
3) arose because there
is no ‘‘natural’’ default date (the Big Bang is too far in the past and not precisely associated with
our everyday dates)
...
For example, the problem with containers of elements without default values is often best solved by not allocating elements until you have proper values for them (e
...
, using push_back())
...
3
...
An initializer-list constructor is used to construct objects using a {}-list as its initializer

496

Construction, Cleanup, Copy, and Move

value
...
g
...
(§31
...
2, §31
...
3)
...
456, 99
...
For example:
void f(initializer_list);
f({1,2});
f({23,345,4567,56789});
f({});
// the empty list
f{1,2};

// error: function call () missing

years
...
That is, all elements must
be of the template argument type, T, or implicitly convertible to T
...
3
...
1 initializer_list Constructor Disambiguation
When you have several constructors for a class, the usual overload resolution rules (§12
...
For selecting a constructor, default and initializer lists take precedence
...

• If both an initializer-list constructor and an ‘‘ordinary constructor’’ could be invoked, prefer
the initializer-list constructor
...
3
...
1

initializer_list

Constructor Disambiguation

497

The first rule, ‘‘prefer the default constructor,’’ is basically common sense: pick the simplest constructor when you can
...

The second rule, ‘‘prefer the initializer-list constructor,’’ is necessary to avoid different resolutions based on different numbers of elements
...
4):
vector v1 {1};
vector v2 {1,2};
vector v3 {1,2,3};

// one element
// two elements
// three elements

vector vs1 {"one"};
vector vs2 {"one", "two"};
vector vs3 {"one", "two", "three"};

In every case, the initializer-list constructor is used
...
3
...
2 Use of initializer_lists
A function with an initializer_list argument can access it as a sequence using the member functions begin(), end(), and size()
...
size(); ++i)
cout << args
...

An initializer_list is passed by value
...
3) and does not impose overhead because an initializer_list object is just a small handle
(typically two words) to an array of Ts
...
begin(); p!=args
...
However, since vector, map, etc
...
)
already #include , so you rarely have to do so directly
...
Don’t even think about trying to modify their
values
...
begin() = val;
// error : attempt to change the value of an initializer-list element
return ∗x
...
That would have done serious damage to some of our most fundamental concepts
...
3
...
5
...

A container might implement an initializer-list constructor like this:
template
class Vector {
public:
Vector(std::initializer_list s); // initializer-list constructor
//
...
size()}
// set vector size
{
reserve(sz);
// get the right amount of space
uninitialized_copy(s
...
end(), elem);
// initialize elements in elem[0:s
...
3)
...
3
...
3 Direct and Copy Initialization
The distinction between direct initialization and copy initialization (§16
...
6) is maintained for {}
initialization
...
3
...
3

Direct and Copy Initialization

499

• The container’s initializer-list constructor can be explicit or not
...

For a vector>, we can see the direct initialization vs
...
For example:
vector> vs = {
{10,11,12,13,14},
{10},
10,

// OK: vector of five elements
// OK: vector of one element
// error : vector(int) is explicit

vector{10,11,12,13}, // OK: vector of five elements
vector{10},
// OK: vector of one element with value 10
...
0
};

A container can have some constructors explicit and some not
...
For example, std::vector(int) is explicit, but std::vector(initialize_list)
is not:
vector v1(7);
vector v2 = 9;

// OK: v1 has 7 elements; note: uses () rather than {}
// error: no conversion from int to vector

void f(const vector&);
void g()
{
v1 = 9;
// error: no conversion from int to vector
f(9);
// error: no conversion from int to vector
}

By replacing () with {} we get:
vector v1 {7};
vector v2 = {9};

// OK: v1 has one element (with the value 7)
// OK: v2 has one element (with the value 9)

void f(const vector&);
void g()
{
v1 = {9};
// OK: v1 now has one element (with the value 9)
f({9});
// OK: f is called with the list {9}
}

Obviously, the results are dramatically different
...
Note that
the apparent ambiguities (in the eyes of the human reader but not the compiler) do not emerge for
longer lists
...
4 Member and Base Initialization
Constructors can establish invariants and acquire resources
...


17
...
1 Member Initialization
Consider a class that might be used to hold information for a small organization:
class Club {
string name;
vector members;
vector officers;
Date founded;
//
...
Arguments
for a member’s constructor are specified in a member initializer list in the definition of the constructor of the containing class
...

}

The member initializer list starts with a colon, and the individual member initializers are separated
by commas
...
4
...
2
...
The constructors are called in the order in which the members are declared
in the class rather than the order in which the members appear in the initializer list
...
Hope for a compiler
warning if you don’t get the order right
...

If a member constructor needs no arguments, the member need not be mentioned in the member
initializer list
...

}

This constructor is equivalent to the previous version
...

It is usually a good idea to be explicit about initializing members
...
3
...

A constructor can initialize members and bases of its class, but not members or bases of its
members or bases
...
*/};
struct BB : B { /*
...

};

17
...
1
...
For example:
class X {
const int i;
Club cl;
Club& rc;
//
...
5, §7
...
3
...
However, for
most types the programmer has a choice between using an initializer and using an assignment
...
Often, there also is an efficiency advantage to using the initializer syntax (compared
to using an assignment)
...

Person(const Person&);
Person(const string& n, const string& a);
};
Person::Person(const string& n, const string& a)
: name{n}
{
address = a;
}

Here name is initialized with a copy of n
...


17
...
2 Base Initializers
Bases of a derived class are initialized in the same way non-data members are
...
If we want to, we
can explicitly specify default construction
...
Bases are initialized before members and destroyed after members (§17
...
3)
...
4
...
Both ‘‘solutions’’ are common (because older versions
of C++ didn’t offer anything better)
...
4
...
2
...
1
//
...
Both get in the way of maintainability
...
2
...
1
//
...
Such a constructor is called a delegating constructor (and
occasionally a forwarding constructor)
...
For example:
class X {
int a;
public:
X(int x) { if (0X() :X{42}, a{56} { }
// error
//
...
Consider:
class X {
int a;
public:
X(int x) { if (0X() { X{42}; } // likely error
//
...
Such use is
more often than not a bug
...

An object is not considered constructed until its constructor completes (§6
...
2)
...
A destructor will not be

504

Construction, Cleanup, Copy, and Move

Chapter 17

called for an object unless its original constructor completed
...
4
...


17
...
4 In-Class Initializers
We can specify an initializer for a non-static data member in the class declaration
...

By default, a constructor will use such an in-class initializer, so that example is equivalent to:
class A {
public:
int a;
int b;
A() : a{7}, b{77} {}
};

Such use of in-class initializers can save a bit of typing, but the real benefits come in more complicated classes with multiple constructors
...
For example:
class A {
public:
A() :a{7}, b{5}, algorithm{"MD5"}, state{"Constructor run"} {}
A(int a_val) :a{a_val}, b{5}, algorithm{"MD5"}, state{"Constructor run"} {}
A(D d) :a{7}, b{g(d)}, algorithm{"MD5"}, state{"Constructor run"} {}
//
...
To make the common values explicit, we can factor
out the unique initializer for data members:
class A {
public:
A() :a{7}, b{5} {}
A(int a_val) :a{a_val}, b{5} {}
A(D d) :a{7}, b{g(d)} {}
//
...
4
...
So we can simplify further:
class A {
public:
A() {}
A(int a_val) :a{a_val} {}
A(D d) :b{g(d)} {}
//
...

// the meaning of 5 for b is
...

An in-class member initializer can use names that are in scope at the point of their use in the
member declaration
...
2
...
The value of the global variable is obtained at the point where the constructor for a new S object is run, so it can (and in this example does) change
...

It is a bad idea to hide subtle dependencies on global data in member initializers
...
4
...
Generally,
the static member declaration acts as a declaration for a definition outside the class
...

static int node_count;
};
int Node::node_count = 0;

// declaration

// definition

However, for a few simple special cases, it is possible to initialize a static member in the class declaration
...
4
...
For example:
class Curious {
public:
static const int c1 = 7;
static int c2 = 11;
const int c3 = 13;
static const int c4 = sqrt(9);
static const float c5 = 7
...

};

// OK
// error : not const
// OK, but not static (§17
...
4)
// error : in-class initializer not constant
// error : in-class not integral (use constexpr rather than const)

If (and only if) you use an initialized member in a way that requires it to be stored as an object in
memory, the member must be (uniquely) defined somewhere
...
For example:
template
class Fixed { // fixed-size array
public:
static constexpr int max = N;
//
...
4) offer an alternative for defining symbolic constants within a class
declaration
...

};

Section 17
...
5 Copy and Move
When we need to transfer a value from a to b, we usually have two logically distinct options:
• Copy is the conventional meaning of x=y; that is, the effect is that the values of x and y are
both equal to y’s value before the assignment
...
For the most interesting cases, containers, that moved-from state is ‘‘empty
...

Typically, a move cannot throw, whereas a copy might (because it may need to acquire a
resource), and a move is often more efficient than a copy
...
Also, standard-library
algorithms rely on being able to assign to (using move or copy) a moved-from object
...

To save us from tedious repetitive work, copy and move have default definitions (§17
...
2)
...
5
...
A copy constructor is supposed to make a copy of an
object without modifying it
...
My opinion is that doing so causes more confusion than it is worth, so my discussion of
copy assumes that the two operations have the conventional types
...

};

// move constructor
// move assignment

508

Construction, Cleanup, Copy, and Move

Chapter 17

First we note that the default copy (copy the members) would be disastrously wrong: the Matrix elements would not be copied, the Matrix copy would have a pointer to the same elements as the
source, and the Matrix destructor would delete the (shared) elements twice (§3
...
1)
...
dim},
elem{new T[m
...
elem,m
...
size(),elem);
}

// copy elements

template
Matrix& Matrix::operator=(const Matrix& m)
// copy assignment
{
if (dim[0]!=m
...
dim[1])
throw runtime_error("bad size in Matrix =");
copy(m
...
elem+m
...

The Matrix copy assignment operator has the property that if a copy of an element throws an
exception, the target of the assignment may be left with a mixture of its old value and the new
...
2)
...
Obviously, this operator=() works only if
the implementation swap() does not use assignment (std::swap() does not); see §17
...
2
...
4
...
If a copy constructor
cannot copy an element (e
...
, because it needs to acquire an unavailable resource to do so), it can
throw an exception
...
The reason I
did not test is that self-assignment of the members is already safe: both my implementations of
Matrix’s copy assignment will work correctly and reasonably efficiently for m=m
...


Section 17
...
1
...
5
...
1 Beware of Default Constructors
When writing a copy operation, be sure to copy every base and member
...
s}, v{a
...

};

Here, I ‘‘forgot’’ to copy s2, so it gets default initialized (to "")
...
It is
also unlikely that I would make this mistake for a simple class
...
Worse, when someone long after the initial design adds a member to a
class, it is easy to forget to add it to the list of members to be copied
...
6)
...
5
...
2 Copy of Bases
For the purposes of copying, a base is just a member: to copy an object of a derived class you have
to copy its bases
...

};
struct B2 {
B2(int);
B2(const B2&);
//
...
m1}, m2{a
...


510

Construction, Cleanup, Copy, and Move

Chapter 17

A virtual base (§21
...
5) may appear as a base of several classes in a hierarchy
...
6) will correctly copy it
...
Where the base object is small and the virtual base
occurs only a few times in a hierarchy, that can be more efficient than techniques for avoiding the
replicated copies
...
5
...
3 The Meaning of Copy
What does a copy constructor or copy assignment have to do to be considered ‘‘a proper copy operation’’? In addition to be declared with a correct type, a copy operation must have the proper copy
semantics
...
To be suitable for
value-oriented programming in general (§16
...
4), and for use with the standard library in particular
(§31
...
2), the operation must meet two criteria:
• Equivalence: After x=y, operations on x and y should give the same result
...

• Independence: After x=y, operations on x should not implicitly change the state of y, that is
f(x) does not change the value of y as long as f(x) doesn’t refer to y
...
Copy operations that provide equivalence and independence lead to simpler and more maintainable code
...
A copy that provides equivalence and independence is part of the notion of a regular type (§24
...
1)
...
People rarely violate this requirement deliberately, and the default copy operations do not violate it; they do memberwise copy (§17
...
1,
§17
...
2)
...
Also, it is not uncommon for an object to contain members
that are not considered part of its value
...

Similarly, counters for statistics gathering and cached values are sometimes not simply copied
...
In
particular, x=y should imply x==y
...
5
...
4) can lead to ‘‘copies’’ that
behave differently, and is most often a bad mistake
...
Most of the problems related to (lack of) independence have to do with objects that contain pointers
...
A default copy operation copies a pointer member, but does not copy the object (if any)
that it points to
...
5
...
3

The Meaning of Copy

void f()
{
S y {x};

511

// ‘‘copy’’ x

∗y
...
p = 2;
delete y
...
p = new int{3};
∗x
...
After the ‘‘copy’’ of x into y, we can manipulate part of
x’s state through y
...
’’
The obvious alternative of copying the complete state of an object is called deep copy
...
3
...
5
...

A shallow copy leaves two objects (here, x and y) with a shared state, and has a huge potential
for confusion and errors
...
It is not possible to reason about an entangled object in
isolation
...
p can
have dramatically different effects
...
Often, it is not obvious that entanglement
has happened until probems arise
...
The original author of S may be aware of the entanglement
and prepared to cope with it, but someone naively assuming that copying an S meant copying its
complete value could be surprised, and someone who finds an S deeply nested in other classes
could be very surprised
...
For example:
struct S2 {
shared_ptr p;
};
S2 x {new int{0}};

512

Construction, Cleanup, Copy, and Move

void f()
{
S2 y {x};
∗y
...
p = 2;
y
...
reset(new int{3});
∗x
...
Entangled objects lead to code that is very hard to manage without some form of
garbage collection (e
...
, shared_ptrs)
...
Who can update the pointed-to object? How? When? If we are running in a multithreaded system, is synchronization needed for access to the shared data? How can we be sure?
Entangled objects (here, resulting from a shallow copy) is a source of complexity and errors that is
at best partially solved by garbage collection (in any form)
...
Unless we compare addresses, we cannot
tell whether two equal values happen to be represented as one or two copies
...
For example, objects passed by value are rarely
written to
...
The idea is that a copy doesn’t
actually need independence until a shared state is written to, so we can delay the copying of the
shared state until just before the first write to it
...

Image(const Image& a);
// copy constructor
//
...

private:
Representation∗ clone();
// copy *rep
Representation∗ rep;
bool shared;
};

Assume that a Representation can be huge and that a write_block() is expensive compared to testing
a bool
...
rep},
shared{true}
{
}

// do shallow copy and prepare for copy-on-write

We protect the argument to that copy constructor by copying the Representation before a write:

Section 17
...
1
...
now we can safely write to our own copy of rep
...


17
...
1
...
When applied
to a copy operation, this simple and necessary rule (§3
...
4, §20
...

Consider:
struct Base {
int b;
Base(const Base&);
//
...

};
void naive(Base∗ p)
{
B b2 = ∗p;
// may slice: invokes Base::Base(const Base&)
//
...

}

// slices: invokes Base::Base(const Base&), not Derived::Derived(const Derived&)

The variables b2 and bb contain copies of the Base part of d, that is, a copy of d
...
The member d
...
This phenomenon is called slicing
...
g
...
5
...
2 where we pass selected information to a base class), but typically it is a subtle bug
...
6
...

Prevent conversion of a pointer to a derived to a pointer to a base: make the base class a
private or protected base (§20
...

The former would make the initializations of b2 and bb errors; the latter would make the call of
naive() and the initialization of bb errors
...
5
...
For an integer in a computer’s memory, that’s just about the only thing that makes sense: that’s what the hardware can do with a single
instruction
...
Consider the obvious
implementation of swap() exchanging the value of two objects:
template
void swap(T& a, T& b)
{
const T tmp = a;
a = b;
b = tmp;
};

// put a copy of a into tmp
// put a copy of b into a
// put a copy of tmp into b

After the initialization of tmp, we have two copies of a’s value
...
After the assignment to b, we have two copies of tmp’s value (that is,
the original value of a)
...
That sounds like a lot of work, and it can be
...
vs2);
swap(m1,m2);
}

What if s1 has a thousand characters? What if vs2 has a thousand elements each of a thousand
characters? What if m1 is a 1000∗1000 matrix of doubles? The cost of copying those data structures could be significant
...
That is, effort has been made to avoid copying (taking
advantage of the fact that string and vector objects really are just handles to their elements)
...
If the only operation we have is copy, similar work must be done for huge numbers of functions and data structures
that are not part of the standard
...

We can also look at the issue of copying from a completely different point of view: we don’t
usually copy physical things unless we absolutely have to
...
If I lend you my car, I give you a key and

Section 17
...
2

Move

515

you drive away in my car, rather than in your freshly made copy of my car
...
Consequently, we talk about ‘‘giving away,’’ ‘‘handing
over,’’ ‘‘transferring ownership of,’’ and ‘‘moving’’ physical objects
...

Examples are locks, sockets, file handles, threads, long strings, and large vectors
...
In particular, we can define move constructors and move assignments to move rather than copy their argument
...
5
...

};

The && indicates an rvalue reference (§7
...
2)
...
For a return value, the move constructor is chosen
...
For example:
template
Matrix::Matrix(Matrix&& a)
:dim{a
...
elem}
{
a
...
elem = nullptr;
}

// move constructor
// grab a’s representation
// clear a’s representation

For the move assignment, we can simply do a swap
...
dim);
// swap representations
swap(elem,a
...
However, the argument of a move operation must always
be left in a state that the destructor can cope with (and preferably deal with very cheaply and easily)
...
In particular, move operations typically do not throw exceptions; they don’t
acquire resources or do complicated operations, so they don’t need to
...
5)
...
However, in general we have to tell it by giving an rvalue reference argument
...
5
...
’’ That is, std::move(x) does not move anything;
instead, it allows a user to move x
...


Standard-library containers have move operations (§3
...
2, §35
...
1) and so have other standardlibrary types, such as pair (§5
...
3, §34
...
4
...
2
...
3
...
Furthermore, operations that insert new elements into standard-library containers, such as insert() and push_back(),
have versions that take rvalue references (§7
...
2)
...

What if we try to swap objects of a type that does not have a move constructor? We copy and
pay the price
...
It is not the
compiler’s job to decide what is excessive and what is necessary
...
6)
...

As usual, you have to be careful about data structures containing pointers (§3
...
1)
...


Section 17
...
2

Move

517

Having move operations affects the idiom for returning large objects from functions
...
dim[0]!=b
...
dim[1]!=b
...
dim[0],a
...
size();
for (int i = 0; i!=n; ++i)
res
...
elem[i]+b
...
’’
Without move operations, we have performance problems and must resort to workarounds
...


17
...
By default, a class provides:
• A default constructor: X()
• A copy constructor: X(const X&)
• A copy assignment: X& operator=(const X&)
• A move constructor: X(X&&)
• A move assignment: X& operator=(X&&)
• A destructor: ˜X()

518

Construction, Cleanup, Copy, and Move

Chapter 17

By default, the compiler generates each of these operations if a program uses it
...

• If the programmer declares a copy operation, a move operation, or a destructor for a class,
no copy operation, move operation, or destructor is generated for that class
...
However, that generation is deprecated in the ISO standard (§iso
...

If necessary, we can be explicit about which functions are generated (§17
...
1) and which are not
(§17
...
4)
...
6
...
Also, some people prefer to see a complete list of operations in the program
text even if that complete list is not needed
...

};

This fragment of the implementation of std::gslice (§40
...
6) is equivalent to:
class gslice {
valarray size;
valarray stride;
valarray d1;
public:
//
...

Using =default is always better than writing your own implementation of the default semantics
...
6
...

gslice(const gslice& a);
};
gslice::gslice(const gslice& a)
: size{a
...
stride},
d1{a
...
For example, I might forget to copy one of the members and get it
default initialized (rather than copied)
...
For the
default operations, those optimizations can be significant
...
6
...
That is, we get
memberwise copy, memberwise default construction, etc
...
a and s0
...
The return of s1 moves s1
...
b, leaving s1
...
b unchanged
...
That’s the simplest
and fastest thing for the compiler to do
...

The default moved-from state is one for which the default destructor and default copy assignment work correctly
...
If you need stronger guarantees, write your own operations
...
6
...
If they were not linked, errors that are obvious when you think about them would not be
caught by the compiler
...
6
...
1 Default Constructors
Consider:
struct X {
X(int);
};

// require an int to initialize an X

By declaring a constructor that requires an integer argument, the programmer clearly states that a
user needs to provide an int to initialize an X
...
We have:
X a {1};
X b {};

// OK
// error: no default constructor

If we also want the default constructor, we can define one or declare that we want the default generated by the compiler
...
e
...
Here, Y() sets s to
the empty string
...
Sigh! Hope for a compiler warning
...
6
...
2 Maintaining Invariants
Often, a class has an invariant
...
Unfortunately, the compiler cannot in every case know
what a programmer considers an invariant
...
Furthermore, the programmer did not leave a hint about how that invariant is to be established and
maintained
...
That invariant is

Section 17
...
3
...
The result is that a Z can be copied and moved using the default operations:
Z v0;
Z val {{1,2,3},1,&val[2]};
Z v2 = val;
Z v3 = move(val);

// no initialization (oops! possibility of undefined values)
// OK, but ugly and error-prone
// copies: v2
...
elem becomes empty; v3
...
The root problem is that Z is badly designed because critical information is ‘‘hidden’’ in a comment or completely missing
...
Wherever possible
[1] Establish an invariant in a constructor (including possibly resource acquisition)
...

[3] Do any needed cleanup in the destructor (incl
...


17
...
3
...
Consider a
simple Handle:
template class Handle {
T∗ p;
public:
Handle(T∗ pp) :p{pp} { }
T& operator∗() { return ∗p; }
˜Handle() { delete p; }
};

The idea is that you construct a Handle given a pointer to an object allocated using new
...
For example:
void f1()
{
Handle h {new int{99}};
//
...
That’s good because a default constructor could leave Handle::p uninitialized:
void f2()
{
Handle h; // error: no default constructor
//
...

Also, Handle declares a destructor: this suppresses the generation of copy and move operations
...
Consider:

522

Construction, Cleanup, Copy, and Move

void f3()
{
Handle h1 {new int{7}};
Handle h2 {h1};
//
...
The results would be undefined and most likely disastrous (§3
...
1)
...
In general, if a class has a pointer member, the
default copy and move operations should be considered suspicious
...
If that pointer member does not represent ownership
and memberwise copy is appropriate, explicit =default and a comment are most likely a good idea
...

Handle(const T& a) :p{new T{∗a
...
6
...
4 Partially Specified Invariants
Troublesome examples that rely on invariants but only partially express them through constructors
or destructors are rarer but not unheard of
...
at(i) = arg
...
at(i);
return ∗this;
}
//
...

enum State { empty, nought, cross };
private:
vector pos;
};

This was reported to have been part of a real program
...
Also, it explicitly implements the copy assignment, but not the copy constructor
...


Section 17
...
3
...
That destructor can be
because all it needs to do is to ensure that the member pos is destroyed, which is what
would have been done anyway had the copy assignment not been defined
...
Add a copy constructor for completeness and we get:
=default

class Tic_tac_toe {
public:
Tic_tac_toe(): pos(9) {} // always 9 positions
Tic_tac_toe(const Tic_tac_toe&) = default;
Tic_tac_toe& operator=(const Tic_tac_toe& arg) = default;
˜Tic_tac_toe() = default;
//
...

enum State { empty, nought, cross };
private:
vector pos;
};

Looking at this, we realize that the net effect of these =defaults is just to eliminate move operations
...
When we made the copy assignment =default, we eliminated
the nasty dependence on the magic constant 9
...
The
simplest way to do that is to remove the explicit =defaults, and then we see that Tic_tac_toe is really
a perfectly ordinary type:
class Tic_tac_toe {
public:
//
...

enum State { empty, nought, cross };
private:
vector pos {Vector(9)};
};

// always 9 positions

One conclusion that I draw from this and other examples where an ‘‘odd combination’’ of the
default operations is defined is that we should be highly suspicious of such types: their irregularity
often hides design flaws
...
g
...
g
...
g
...


524

Construction, Cleanup, Copy, and Move

Chapter 17

17
...
4 deleted Functions
We can ‘‘delete’’ a function; that is, we can state that a function does not exist so that it is an error
to try to use it (implicitly or explicitly)
...
For example, it is common to want to prevent the copying of classes used as bases
because such copying easily leads to slicing (§17
...
1
...

Base& operator=(const Base&) = delete;// disallow copying
Base(const Base&) = delete;
Base& operator=(Base&&) = delete;
Base(Base&&) = delete;

// disallow moving

};
Base x1;
Base x2 {x1}; // error : no copy constructor

Enabling and disabling copy and move is typically more conveniently done by saying what we
want (using =default; §17
...
1) rather than saying what we don’t want (using =delete)
...
For example, we can eliminate a specialization from
the set of possible specializations of a function template:
template
T∗ clone(T∗ p) // return copy of *p
{
return new T{∗p};
};
Foo∗ clone(Foo∗) = delete;
void f(Shape∗ ps, Foo∗ pf)
{
Shape∗ ps2 = clone(ps);
Foo∗ pf2 = clone(pf);
}

// don’t try to clone a Foo

// fine
// error : clone(Foo*) deleted

Another application is to eliminate an undesired conversion
...

Z(double);
Z(int) = delete;
};
void f()
{
Z z1 {1};
Z z2 {1
...
6
...

˜Not_on_stack() = delete;
};
class Not_on_free_store {
//
...
2
...
2
...
For example:
void f()
{
Not_on_stack v1;
Not_on_free_store v2;

// error : can’t destroy
// OK

Not_on_stack∗ p1 = new Not_on_stack;
// OK
Not_on_free_store∗ p2 = new Not_on_free_store; // error : can’t allocate
}

However, we can never delete that Not_on_stack object
...
2
...

Note the difference between a =deleted function and one that simply has not been declared
...
In the latter case, the compiler looks for alternatives, such as not invoking a destructor or using a global operator new()
...
7 Advice
[1]
[2]
[3]

Design constructors, assignments, and the destructor as a matched set of operations; §17
...

Use a constructor to establish an invariant for a class; §17
...
1
...
2
...

[4] If a class has a virtual function, it needs a virtual destructor; §17
...
5
...
3
...

[6] Prefer {} initialization over = and () initialization; §17
...
2
...
3
...

[8] If a class is a container, give it an initializer-list constructor; §17
...
4
...
4
...

[10] If a class has a reference member, it probably needs copy operations (copy constructor and
copy assignment); §17
...
1
...


526

[11]
[12]
[13]
[14]
[15]
[16]
[17]
[18]
[19]
[20]
[21]
[22]
[23]
[24]
[25]

Construction, Cleanup, Copy, and Move

Chapter 17

Prefer member initialization over assignment in a constructor; §17
...
1
...

Use in-class initializers to provide default values; §17
...
4
...
5
...
5
...
1
...
5
...
3
...
5
...
3
...
5
...
3
...
5
...
4
...
6
...
6
...
3
...
6
...
3
...
6
...
6
...
2
...
5
...

When adding a new member to a class, check to see if there are user-defined constructors that
need to be updated to initialize the member; §17
...
1
...

– Humpty Dumpty









Introduction
Operator Functions
Binary and Unary Operators; Predefined Meanings for Operators; Operators and UserDefined Types; Passing Objects; Operators in Namespaces
A Complex Number Type
Member and Nonmember Operators; Mixed-Mode Arithmetic; Conversions; Literals;
Accessor Functions; Helper Functions
Type Conversion
Conversion Operators; explicit Conversion Operators; Ambiguities
Advice

18
...
For
example, because of long acquaintance,
x+y∗z

is clearer to us than
multiply y by z and add the result to x

It is hard to overestimate the importance of concise notation for common operations
...
However, most concepts for which operators are conventionally used are not built-in types in C++, so they must be

528

Operator Overloading

Chapter 18

represented as user-defined types
...
Defining operators for such classes sometimes allows a programmer to provide a more conventional and convenient notation for manipulating objects than could be achieved using only the basic functional
notation
...
A complex is represented by a pair of double-precision floating-point numbers manipulated by the operators + and ∗
...
For example, if b and c are of type complex, b+c means b
...
We can
now approximate the conventional interpretation of complex expressions:
void f()
{
complex a = complex{1,3
...
2, 2};
complex c {b};
a = b+c;
b = b+c∗a;
c = a∗b+complex(1,2);
}

The usual precedence rules hold, so the second statement means b=b+(c∗a), not b=(b+c)∗a
...
g
...


Section 18
...
However, the
usefulness of user-defined operators is not restricted to numeric types
...


18
...
3) can be declared:
+
|
−=
<<
>=
−>


˜
∗=
>>
&&
[]


!
/=
>>=
||
()

/
=
%=
<<=
++
new

%
<
ˆ=
==
−−
new[]

ˆ
>
&=
!=
−>∗
delete

&
+=
|=
<=
,
delete[]

The following operators cannot be defined by a user:
::
scope resolution (§6
...
4, §16
...
12)

...
2)

...
6)
They take a name, rather than a value, as their second operand and provide the primary means of
referring to members
...

The named ‘‘operators’’cannot be overloaded because they report fundamental facts about their operands:
sizeof
size of object (§6
...
8)
alignof
alignment of object (§6
...
9)
typeid
type_info of an object (§22
...
4
...
2
...
This is a
kind of syntactic subterfuge because there is no operator called ""
...
4)
...
For example, use pow(), not ∗∗
...
For example, defining an operator ∗∗ to mean exponentiation may seem an obvious and easy task, but think again
...
However, it is most uncertain if applying subtle technical rules will lead to more readable and maintainable code
...

The name of an operator function is the keyword operator followed by the operator itself, for
example, operator<<
...
A
use of the operator is only a shorthand for an explicit call of the operator function
...
operator+(b);
}

// shor thand
// explicit call

Given the previous definition of complex, the two initializers are synonymous
...
2
...
For any binary operator @, aa@bb can be interpreted
as either aa
...
If both are defined, overload resolution (§12
...
For example:
class X {
public:
void operator+(int);
X(int);
};
void operator+(X,X);
void operator+(X,double);
void f(X a)
{
a+1;
1+a;
a+1
...
operator+(1)
// ::operator+(X(1),a)
// ::operator+(a,1
...
For any prefix unary operator
@, @aa can be interpreted as either aa
...
If both are defined, overload
resolution (§12
...
For any postfix unary operator
@, aa@ can be interpreted as either aa
...
This is explained further
in §19
...
4
...
3) determines which, if any, interpretation
is used
...
A)
...
Consider:
class X {
public:

// members (with implicit this pointer):

X∗ operator&();
X operator&(X);
X operator++(int);
X operator&(X,X);
X operator/();
};

// prefix unary & (address of)
// binar y & (and)
// postfix increment (see §19
...
4)
// error : ternary
// error : unar y /

Section 18
...
1

Binary and Unary Operators

531

// nonmember functions :
X operator−(X);
X operator−(X,X);
X operator−−(X&,int);
X operator−();
X operator−(X,X,X);
X operator%(X);

// prefix unary minus
// binar y minus
// postfix decrement
// error : no operand
// error : ternary
// error : unar y %

Operator [] is described in §19
...
1, operator () in §19
...
2, operator −> in §19
...
3, operators ++ and
−− in §19
...
4, and the allocation and deallocation operators in §11
...
4 and §19
...
5
...
2
...
2
...
2
...
2
...

The default meaning of &&, ||, and , (comma) involves sequencing: the first operand is evaluated
before the second (and for && and || the second operand is not always evaluated)
...


18
...
2 Predefined Meanings for Operators
The meanings of some built-in operators are defined to be equivalent to some combination of other
operators on the same arguments
...
Such relations do not hold for user-defined operators unless the user defines them to
...

The operators = (assignment), & (address-of), and , (sequencing; §10
...
2) have predefined meanings when applied to class objects
...
6
...

void operator=(const X&) = delete;
void operator&() = delete;
void operator,(const X&) = delete;
//
...


532

Operator Overloading

Chapter 18

18
...
3 Operators and User-Defined Types
An operator function must either be a member or take at least one argument of a user-defined type
(functions redefining the new and delete operators need not)
...
In particular, it is not possible to define an operator function that operates exclusively on
pointers
...

An operator function intended to accept a built-in type (§6
...
1) as its first operand cannot be a
member function
...
operator+(2), but 2+aa cannot because
there is no class int for which to define + to mean 2
...
Even if there were, two different
member functions would be needed to cope with 2+aa and aa+2
...
This example is trivially handled using one or more nonmember functions
(§18
...
2, §19
...

Enumerations are user-defined types so that we can define operators for them
...
Where a user-defined operator provides a possible
interpretation, the expression is checked according to the overload resolution rules in §12
...


18
...
4 Passing Objects
When we define an operator, we typically want to provide a conventional notation, for example,
a=b+c
...
For example, we cannot require pointer arguments and expect programmers to use the address-of operator or return a pointer and expect the user to dereference it:
∗a=&b+&c is not acceptable
...
2):
• Pass-by-value
• Pass-by-reference
For small objects, say, one to four words, call-by-value is typically a viable alternative and often the
one that gives the best performance
...
For example, assume that a Point is represented as a
pair of ints:
void Point::operator+=(Point delta);

// pass-by-value

Section 18
...
4

Passing Objects

Larger objects, we pass by reference
...
5
...
2
...

Typically, an operator returns a result
...
Instead, return objects by value
...
3
...
5
...
For example:
Matrix operator+(const Matrix& a, const Matrix& b)
{
Matrix res {a};
return res+=b;
}

// return-by-value

Note that operators that return one of their argument objects can – and usually do – return a reference
...
dim[0] || dim[1]!=a
...
elem;
double∗ end = p+dim[0]∗dim[1];
while(p!=end)
∗p++ += ∗q++
return ∗this;
}

This is particularly common for operator functions that are implemented as members
...
4
...
5
...
1, §28
...
3)
...
2
...
Consider this simplified version of string I/O from the standard library:
namespace std {
class string {
//
...

ostream& operator<<(const char∗);
};

// output C-style string

extern ostream cout;
ostream& operator<<(ostream&, const string&);
} // namespace std

// output std::string

int main()
{
const char∗ p = "Hello";
std::string s = "world";
std::cout << p << ", " << s << "!\n";
}

Naturally, this writes out
accessible by writing:

Hello, world!
...
In other words, I was on my best behavior and
didn’t pollute the global namespace or in other ways introduce unnecessary dependencies
...
operator<<(p)

However, std::ostream doesn’t have a member function to output a std::string, so
std::cout << s

means
operator<<(std::cout,s)

Operators defined in namespaces can be found based on their operand types just as functions can be
found based on their argument types (§14
...
4)
...
In that way, the compiler finds and uses:
std::operator<<(std::ostream&, const std::string&)

Consider a binary operator @
...

Declarations for several operator@s may be found and overload resolution rules (§12
...
This lookup mechanism is applied only if the operator has at least one

Section 18
...
5

Operators in Namespaces

535

operand of a user-defined type
...
3
...
4) will be considered
...
5)
...

Note that in operator lookup no preference is given to members over nonmembers
...
2
...
The lack of hiding of operators ensures that built-in
operators are never inaccessible and that users can supply new meanings for an operator without
modifying existing class declarations
...
*/ return !x; }
int f(int x) { /*
...
4
...


18
...
1 is too restrictive to please anyone
...
3};
complex d {2+b};
b = c∗2∗c;
}

In addition, we would expect to be provided with a few additional operators, such as == for comparison and << for output, and a suitable set of mathematical functions, such as sin() and sqrt()
...
3
...

The complex type developed in this section uses double for its scalars and is roughly equivalent
to the standard-library complex (§40
...


18
...
1 Member and Nonmember Operators
I prefer to minimize the number of functions that directly manipulate the representation of an
object
...
Operators that simply produce a new value based on
the values of their arguments, such as +, are then defined outside the class and use the essential
operators in their implementation:

536

Operator Overloading

Chapter 18

class complex {
double re, im;
public:
complex& operator+=(complex a); // needs access to representation
//
...

Given these declarations, we can write:
void f(complex x, complex y, complex z)
{
complex r1 {x+y+z}; // r1 = operator+(operator+(x,y),z)
complex r2 {x};
r2 += y;
r2 += z;

// r2 = x
// r2
...
operator+=(z)

}

Except for possible efficiency differences, the computations of r1 and r2 are equivalent
...
This surprises most people at first, but it follows from the fact that three
objects are involved in a + operation (the two operands and the result), whereas only two objects are
involved in a += operation
...
For example:
inline complex& complex::operator+=(complex a)
{
re += a
...
im;
return ∗this;
}

This does not require a temporary variable to hold the result of the addition and is simple for a
compiler to inline perfectly
...

However, we don’t always have a good optimizer, and not all types are as simple as complex, so
§19
...


18
...
2 Mixed-Mode Arithmetic
To cope with 2+z, where z is a complex, we need to define operator + to accept operands of different
types
...
We can achieve that simply by
adding appropriate versions of the operators:

Section 18
...
2

class complex {
double re, im;
public:
complex& operator+=(complex a)
{
re += a
...
im;
return ∗this;
}
complex& operator+=(double a)
{
re += a;
return ∗this;
}
//
...
real()+b,a
...
real(),b
...
3
...

Given these declarations of +, we can write:
void f(complex x, complex y)
{
auto r1 = x+y; // calls operator+(complex,complex)
auto r2 = x+2; // calls operator+(complex,double)
auto r3 = 2+x; // calls operator+(double,complex)
auto r4 = 2+3; // built-in integer addition
}

I added the integer addition for completeness
...
3
...
For example:
complex b {3}; // should mean b
...
im=0
void comp(complex x)
{
x = 4;
// should mean x
...
im=0
//
...
A constructor taking a
single argument specifies a conversion from its argument type to the constructor’s type
...

};

// build a complex from a double

The constructor specifies the traditional embedding of the real line in the complex plane
...
The constructor is used
when a value of a type is expected and when such a value can be created by a constructor from the
value supplied as an initializer or assigned value
...
For example:
complex b {3};

means
complex b {3,0};

A user-defined conversion is implicitly applied only if it is unique (§12
...
If you don’t want a constructor to be used implicitly, declare it explicit (§16
...
6)
...

};

Using default arguments, we can abbreviate:

Section 18
...
3

Conversions

539

class complex {
double re, im;
public:
complex(double r =0, double i =0) : re{r}, im{i} { }
//
...
2
...


void f()
{
complex z;
complex x {1,2};
complex y {x}; // y also has the value {1,2}
z = x;
// z also has the value {1,2}
}

18
...
3
...


This can get tedious, and what is tedious easily becomes error-prone
...
Often these variants are very similar
...

The alternative to providing different versions of a function for each combination of arguments
is to rely on conversions
...
Consequently, we could simply declare only one version of the equality operator for complex:
bool operator==(complex,complex);
void f(complex x, complex y)
{
x==y;
// means operator==(x,y)
x==3;
// means operator==(x,complex(3))
3==y;
// means operator==(complex(3),y)
}

There can be reasons for preferring to define separate functions
...
Where such issues are not significant, relying on conversions and providing only
the most general variant of a function – plus possibly a few critical variants – contain the

540

Operator Overloading

Chapter 18

combinatorial explosion of variants that can arise from mixed-mode arithmetic
...

Unless a best match exists, an expression is ambiguous and is an error (see §12
...

An object constructed by explicit or implicit use of a constructor in an expression is automatic
and will be destroyed at the first opportunity (see §10
...
4)
...
(or a −>)
...
is implicit
...
operator+=(z);
3+=z;
}

// OK: complex(3)+z
// error : 3 is not a class object
// error: 3 is not a class object

Thus, you can approximate the notion that an operator requires an lvalue as its left-hand operand by
making that operator a member
...
2
...
4
...


18
...
4 Literals
We have literals of built-in types
...
2 and 12e3 are literals of type double
...
4)
...

}

Given that, a complex can be constructed from its constituent parts at compile time just like a literal
from a built-in type
...
2,12e3};
constexpr complex z2 {1
...

It is possible to go further and introduce a user-defined literal (§19
...
6) in support of our complex type
...
’’ For example:
constexpr complex operator "" i(long double d)
{
return {0,d}; // complex is a literal type
}

// imaginar y literal

Section 18
...
4

Literals

541

This would allow us to write:
complex z1 {1
...
3i};
return x+sqrt(d+12e3i)+12e3i;
}

This user-defined literal gives us one advantage over what we get from constexpr constructors: we
can use user-defined literals in the middle of expressions where the {} notation can only be used
when qualified by a type name
...
2,12e3};
complex f(double d)
{
complex x {0,2
...
The standard-library complex uses constexpr constructors rather than a userdefined literal
...
3
...
That is not
quite sufficient for real use
...

};

I don’t consider it a good idea to provide individual access to all members of a class; in general, it
is not
...
If we are not careful, individual access could compromise an invariant, and it
typically complicates changes to the representation
...
3 or (even more
so) for the String from §19
...
However, for complex, real() and imag() are semantically significant:
some algorithms are most cleanly written if they can set the real and imaginary parts independently
...
real()==b
...
imag()==b
...
3
...
The definitions
of most of the following helper functions similarly rely on real() and imag()
...
3
...


From a user’s point of view, the complex type presented here is almost identical to the complex found in in the standard library (§5
...
2, §40
...


18
...
2
...
4
...
2
...
e
...

• Implicit; that is, it will be applied wherever it can be used unambiguously (§18
...
3), e
...
, as
a function argument
...
4
...
Also, a constructor cannot specify
[1] an implicit conversion from a user-defined type to a built-in type (because the built-in
types are not classes), or
[2] a conversion from a new class to a previously defined class (without modifying the declaration for the old class)
...
A member
function X::operator T(), where T is a type name, defines a conversion from X to T
...
Tiny throws Bad_range if its operations overflow or underflow:

544

Operator Overloading

Chapter 18

class Tiny {
char v;
void assign(int i) { if (i&˜077) throw Bad_range(); v=i; }
public:
class Bad_range { };
Tiny(int i) { assign(i); }
Tiny& operator=(int i) { assign(i); return ∗this; }
operator int() const { return v; }

// conversion to int function

};

The range is checked whenever a Tiny is initialized by an int and whenever an int is assigned to one
...

To enable the usual integer operations on Tiny variables, we define the implicit conversion from
Tiny to int, Tiny::operator int()
...

Whenever a Tiny appears where an int is needed, the appropriate int is used
...

The istream and ostream types rely on a conversion function to enable statements such as:
while (cin>>x)
cout<
The input operation cin>>x returns an istream&
...
This value can then be tested by the while (see §38
...
4)
...
4
...

In general, it is wise to be sparing in the introduction of conversion operators
...
Such ambiguities are caught by the compiler, but they can be a
nuisance to resolve
...
If such a function becomes popular enough to make explicit use inelegant, it can
be replaced by a conversion operator X::operator int()
...
For example:
int operator+(Tiny,Tiny);
void f(Tiny t, int i)
{
t+i; // error, ambiguous: ‘‘operator+(t,Tiny(i))’’ or ‘‘int(t)+i’’?
}

It is therefore often best to rely on user-defined conversions or user-defined operators for a given
type, but not both
...
4
...
However, it is possible to declare a conversion operator explicit and have it apply only for direct initialization (§16
...
6),
where an equivalent explicit constructor would have been used
...
2
...
3
...

explicit operator bool() const noexcept;
// does *this hold a pointer (that is not nullptr)?
//
...


void use(unique_ptr p, unique_ptr q)
{
if (!p)
// OK: we want this use
throw Invalid_uninque_ptr{};
bool b = p;
int x = p+q;

// error ; suspicious use
// error; we definitly don’t want this

}

Had unique_ptr’s conversion to bool not been explicit, the last two definitions would have compiled
...


546

Operator Overloading

Chapter 18

18
...
3 Ambiguities
An assignment of a value of type V to an object of class X is legal if there is an assignment operator
X::operator=(Z) so that V is Z or there is a unique conversion of V to Z
...

In some cases, a value of the desired type can be constructed by repeated use of constructors or
conversion operators
...
In some cases, a value of the desired type can be constructed in more
than one way; such cases are illegal
...
*/ X(int); X(const char∗); };
class Y { /*
...
*/ Z(X); };
X f(X);
Y f(Y);
Z g(Z);
void k1()
{
f(1);
f(X{1});
f(Y{1});
g("Mack");
g(X{"Doc"});
g(Z{"Suzy"});

// error: ambiguous f(X(1)) or f(Y(1))?
// OK
// OK
// error: two user-defined conversions needed; g(Z{X{"Mack"}}) not tried
// OK: g(Z{X{"Doc"}})
// OK: g(Z{X{"Suzy"}})

}

User-defined conversions are considered only if a call cannot be resolved without them (i
...
, using
only built-in conversions)
...
*/ XX(int); };
void h(double);
void h(XX);
void k2()
{
h(1); // h(double{1}) or h(XX{1})? h(double{1})!
}

The call h(1) means h(double(1)) because that alternative uses only a standard conversion rather than
a user-defined conversion (§12
...

The rules for conversion are neither the simplest to implement, nor the simplest to document,
nor the most general that could be devised
...
It is far easier to manually resolve an
ambiguity than to find an error caused by an unsuspected conversion
...
4
...
For example:
class Quad {
public:
Quad(double);
//
...

Once the types of both sides of an initialization or assignment have been determined, both types
are used to resolve the initialization or assignment
...

};
void g(Real a)
{
double d = a;
int i = a;
d = a;
i = a;

// d = a
...
int();
// d = a
...
int();

}

In these cases, the type analysis is still bottom-up, with only a single operator and its argument
types considered at any one time
...
5 Advice
[1]
[2]
[3]
[4]

Define operators primarily to mimic conventional usage; §18
...

Redefine or prohibit copying if the default is not appropriate for a type; §18
...
2
...
2
...

For large results, use a move constructor; §18
...
4
...
3
...

Prefer nonmember functions over members for operations that do not need access to the representation; §18
...
2
...
2
...

Use nonmember functions for symmetric operators; §18
...
2
...
3
...
1
...
3
...

Provide ‘‘set() and get() functions’’ for a data member only if the fundamental semantics of a
class require them; §18
...
5
...
4
...
4
...

Do not define the same conversion as both a constructor and a conversion operator; §18
...
3
...

– Albert Camus









Introduction
Special Operators
Subscripting; Function Call; Dereferencing; Increment and Decrement; Allocation and Deallocation; User-Defined Literals
A String Class
Essential Operations; Access to Characters; Representation; Member Functions; Helper
Functions; Using Our String
Friends
Finding Friends; Friends and Members
Advice

19
...
In fact, operators are crucial in the
design of containers (e
...
, vector and map; §4
...
g
...
2
...
5), and other classes concerned with resource management
...
2 Special Operators
The operators
[]

()

−>

++

−−

new

delete

are special only in that the mapping from their use in the code to a programmer’s definition differs
slightly from that used for conventional unary and binary operators, such as +, <, and ˜ (§18
...
3)
...


550

Special Operators

Chapter 19

19
...
1 Subscripting
An operator[] function can be used to give subscripts a meaning for class objects
...
This makes it possible to define
vectors, associative arrays, etc
...
7:

std::pairs
...
first) return x
...
push_back({s,0});

// initial value: 0

return vec
...
second;

// return last element (§31
...
2)

}

We can use Assoc like this:
int main()
// count the occurrences of each word on input
{
Assoc values;
string buf;
while (cin>>buf) ++values[buf];
for (auto x : values
...
first << ',' << x
...
4
...
4
...

An operator[]() must be a non-static member function
...
2
...

The call operator, (), can be overloaded in the same way as other operators can
...
2
...

};
void f(Action act)
{
int x = act(2);
auto y = act(3,4);
double z = act(2
...

};

An argument list for an operator()() is evaluated and checked according to the usual argument-passing rules
...
The call
operator is also known as the application operator
...
An object that acts like a
function is often called a function-like object or simply a function object (§3
...
3)
...
In many cases, it is
essential that function objects can hold data needed to perform their operation
...
For example:
void h(vector& vec, list& lst, complex z)
{
for_each(vec
...
end(),Add{2,3});
for_each(lst
...
end(),Add{z});
}

This will add complex{2,3} to every element of the vector and z to every element of the list
...

This all works because for_each is a template that applies () to its third argument without caring
exactly what that third argument really is:

552

Special Operators

Chapter 19

template
Fct for_each(Iter b, Iter e, Fct f)
{
while (b != e) f(∗b++);
return f;
}

At first glance, this technique may look esoteric, but it is simple, efficient, and extremely useful
(§3
...
3, §33
...

Note that a lambda expression (§3
...
3, §11
...
For example, we could have written:
void h2(vector& vec, list& lst, complex z)
{
for_each(vec
...
end(),[](complex& a){ a+={2,3}; });
for_each(lst
...
end(),[](complex& a){ a+=z; });
}

In this case, each of the lambda expressions generates the equivalent of the function object Add
...
2
...
5
...

An operator()() must be a non-static member function
...
2
...
5
...


19
...
3 Dereferencing
The dereferencing operator, −> (also known as the arrow operator), can be defined as a unary postfix operator
...

X∗ operator−>();
};

Objects of class Ptr can be used to access members of class
pointers are used
...
operator->())->m = 7

The transformation of the object p into the pointer p
...
That is the sense in which operator−>() is a unary postfix operator
...
For example:
void g(Ptr p)
{
X∗ q1 = p−>;
X∗ q2 = p
...
2
...
The standard-library ‘‘smart pointers’’ unique_ptr and shared_ptr (§5
...
1) provide operator −>
...
Disk_ptr’s
constructor takes a name that can be used to find the object on disk, Disk_ptr::operator−>() brings the
object into main memory when accessed through its Disk_ptr, and Disk_ptr’s destructor eventually
writes the updated object back out to disk:
template
class Disk_ptr {
string identifier;
T∗ in_core_address;
//
...

};
void update(const string& s)
{
Disk_ptr p {s};
p−>name = "Roscoe";
//
...

For ordinary pointers, use of −> is synonymous with some uses of unary ∗ and []
...
m
(∗p)
...
m
p−>m == p[0]
...
The equivalence can be provided where desired:

554

Special Operators

template
class Ptr {
Y∗ p;
public:
Y∗ operator−>() { return p; }
Y& operator∗() { return ∗p; }
Y& operator[](int i) { return p[i]; }
//
...

The overloading of −> is important to a class of interesting programs and is not just a minor
curiosity
...
Iterators (Chapter 33) provide an
important example of this
...
If used, its return type must be a pointer or
an object of a class to which you can apply −>
...
2
...

Despite the similarity between −> and
...
(dot)
...
2
...
This is especially obvious and necessary where the aim is to replace an ordinary pointer type with a ‘‘smart pointer’’ type
that has the same semantics, except that it adds a bit of run-time error checking
...
We would also like to ensure that p can be incremented and decremented only if it points to an object within an array and the increment and decrement operations
yield an object within that array
...
2
...
Consequently, we must define prefix and postfix increment
and decrement for Ptr
...

This int is never used; the argument is simply a dummy used to distinguish between prefix and postfix application
...
The dummy argument is used only for the ‘‘odd’’ postfix ++ and −−
...
They are not only odd syntactically, they tend
to be marginally harder to implement than the postfix versions, less efficient, and less frequently
used
...
check that ptr+1 can be pointed to
...
check that ptr+1 can be pointed to
...
The post-increment operator must
make a new object to return
...
operator−−(0);
// suffix: p-p
...
operator++();
// prefix: ++p
p
...
A pointer template that behaves correctly with respect to
inheritance is presented in §27
...
2
...
2
...
2
...
Similarly, operator delete
frees its memory by calling an operator delete()
...

Using the standard-library type alias size_t (§6
...
8) for sizes, the declarations of the global versions look like this:
void∗ operator new(size_t);
void∗ operator new[](size_t);
void operator delete(void∗, size_t);
void operator delete[](void∗, size_t);

// use for individual object
// use for array
// use for individual object
// use for array

// for more versions, see §11
...
4

That is, when new needs memory on the free store for an object of type X, it calls operator
new(sizeof(X))
...
A new expression may ask for more memory than is
indicated by N∗sizeof(X), but it will always do so in terms of a number of characters (i
...
, a number
of bytes)
...
After all, someone else might rely on some aspect of the default behavior or
might even have supplied other versions of these functions
...
2
...

This class might be the base for many derived classes
...

void∗ operator new(size_t);
void operator delete(void∗, size_t);
void∗ operator new[](size_t);
void operator delete[](void∗, size_t);
};

Member operator new()s and operator delete()s are implicitly static members
...
They provide storage that a constructor can
initialize and a destructor can clean up
...
2, §11
...
3
// assume p points to s bytes of memory allocated by Employee::operator new()
// and free that memory for reuse
}
}

The use of the hitherto mysterious size_t argument now becomes obvious
...
Deleting a ‘‘plain’’ Employee gives an argument value of sizeof(Employee);
deleting a Manager derived from Employee that does not have its own operator delete() gives an argument value of sizeof(Manager)
...
Naturally, a class-specific allocator can store such information (as a general-purpose allocator must) and ignore the size_t argument to operator delete()
...

How does a compiler know how to supply the right size to operator delete()? The type specified
in the delete operation matches the type of the object being deleted
...
2
...

delete p;
// hope Employee has a virtual destructor

In principle, deallocation is then done by the destructor (which knows the size of its class)
...
2
...
2
...
2
1
...

For example:
"Hi!"s
// string, not ‘‘zero-terminated array of char’’
1
...
56km
// not miles! (units)
1234567890123456789012345678901234567890x // extended-precision

Such user-defined literals are supported through the notion of literal operators that map literals
with a given suffix into a desired type
...
For example:
constexpr complex operator"" i(long double d)
{
return {0,d}; // complex is a literal type
}

// imaginar y literal

std::string operator"" s(const char∗ p, size_t n)
// std::string literal
{
return string{p,n}; // requires free-store allocation
}

These two operators define suffixes i and s, respectively
...
Given those, we can write:

constexpr

to enable compile-time

template void f(const T&);
void g()
{
f("Hello");
f("Hello"s);
f("Hello\n"s);

// pass pointer to char*
// pass (five-character) string object
// pass (six-character) string object

auto z = 2+1i; // complex{2,1}
}

The basic (implementation) idea is that after parsing what could be a literal, the compiler always
checks for a suffix
...
2
...
It is not possible to redefine the meaning of a built-in literal suffix or to augment the syntax of literals
...
2
...
8):
• An integer literal (§6
...
4
...
2
...
1): accepted by a literal operator taking a long double or a
const
char∗
argument or by a template literal operator, for example,
12345678901234567890
...
99s
• A string literal (§7
...
2): accepted by a literal operator taking a (const char∗, size_t) pair of
arguments, for example, "string"s and R"(Foo\bar)"_path
• A character literal (§6
...
3
...

For example, we could define a literal operator to collect digits for integer values that cannot be
represented in any of the built-in integer types:
Bignum operator"" x(const char∗ p)
{
return Bignum(p);
}
void f(Bignum);
f(123456789012345678901234567890123456789012345x);

Here, the C-style string "123456789012345678901234567890123456789012345" is passed to operator""
Note that I did not put those digits in double quotes
...

To get a C-style string from the program source text into a literal operator, we request both the
string and its number of characters
...


string operator"" s(const char∗ p, size_t n);
string s12 = "one two"s;
string s22 = "two\ntwo"s;
string sxx = R"(two\ntwo)"s;

// calls operator ""("one two",7)
// calls operator ""("two\ntwo",7)
// calls operator ""("two\\ntwo",8)

In the raw string (§7
...
2
...

The rationale for requiring the number of characters is that if we want to have ‘‘a different kind
of string,’’ we almost always want to know the number of characters anyway
...
For example:
string operator"" SS(const char∗ p);

// warning: this will not work as expected

string s12 = "one two"SS;
string s13 = 13SS;

// error : no applicable literal operator
// OK, but why would anyone do that?

A literal operator converting numerical values to strings could be quite confusing
...
For example:
template ...
e
...
6) can be disconcerting, but it is the only way of assigning
nonstandard meanings to digits at compile time
...
tail> // peel off one ternar y digit
constexpr int b3_helper()
{
static_assert(c<'3',"not a ternary digit");
return ipow(3,sizeof
...
);
}

Given that, we can define our base 3 literal operator:
template ...
);
}

// base 3, i
...
, ternar y

Many suffixes will be short (e
...
, s for std::string, i for imaginary, m for meter (§28
...
3), and
extended), so different uses could easily clash
...

class Bignum { /*
...
2
...

}
using namespace Numerics::literals;

The standard library reserves all suffixes not starting with an initial underscore, so define your suffixes starting with an underscore or risk your code breaking in the future:
123km
123_km

// reserved by the standard librar y
// available for your use

19
...
This
String is a simplified version of the standard-library string (§4
...
String provides value
semantics, checked and unchecked access to characters, stream I/O, support for range-for loops,
equality operations, and concatenation operators
...

To allow simple interoperability with C-style strings (including string literals (§7
...
2)), I represent strings as zero-terminated arrays of characters
...
That is, a String with only a few characters stores those characters in the class object
itself, rather than on the free store
...
Experience
shows that for a huge number of applications most strings are short
...

To allow Strings to efficiently ‘‘grow’’ by adding characters at the end, I implement a scheme
for keeping extra space for such growth similar to the one used for vector (§13
...
1)
...

Writing a better string class and/or one that provides more facilities is a good exercise
...


19
...
1 Essential Operations
Class String provides the usual set of constructors, a destructor, and assignment operations (§17
...

};

This String has value semantics
...
The alternative would be
to give String pointer semantics
...
Where it makes sense, I prefer value semantics; examples are complex, vector, Matrix, and
string
...
3
...
5
...

The slightly nontrivial representation of String is presented in §19
...
3
...


19
...
2 Access to Characters
The design of access operators for a string is a difficult topic because ideally access is by conventional notation (that is, using []), maximally efficient, and range checked
...
Here, I follow the standard library by providing
efficient unchecked operations with the conventional [] subscript notation plus range-checked at()
operations:
class String {
public:
//
...

};

The idea is to use [] for ordinary use
...
3
...
size(); i++) h ˆ= s[i]>>1;
return h;
}

Access to Characters

563

// unchecked access to s

Here, using the checked at() would be redundant because we correctly access
s
...

We can use at() where we see a possibility of mistakes
...
at(x) << ‘\n';
}

Unfortunately, assuming that people will use at() consistently where mistakes can be made is overly
optimistic, so some implementations of std::string (from which the []/at() convention is borrowed)
also check []
...
However, for serious
string manipulation tasks, a range check on each character access could impose quite noticeable
overhead
...


19
...
3 Representation
The representation for String was chosen to meet three goals:
• To make it easy to convert a C-style string (e
...
, a string literal) to a String and to allow easy
access to the characters of a String as a C-style string
• To minimize the use of the free store
• To make adding characters to the end of a String efficient
The result is clearly messier than a simple {pointer,size} representation, but much more realistic:
class String {
/*
A simple string that implements the short string optimization

size()==sz is the number of elements
if size()<= short_max, the characters are held in the String object itself;
otherwise the free store is used
...

private:
static const int short_max = 15;
int sz;
// number of characters
char∗ ptr;
union {
int space;
// unused allocated space
char ch[short_max+1]; // leave space for terminating 0
};
void check(int n) const
// range check
{
if (n<0 || sz<=n)
throw std::out_of_range("String::at()");
}
// ancillar y member functions:
void copy_from(const String& x);
void move_from(String& x);
};

This supports what is known as the short string optimization by using two string representations:
• If sz<=short_max, the characters are stored in the String object itself, in the array named ch
...
The member named space is the number of such characters
...

In both cases, ptr points to the elements
...
Only the constructors, assignments, moves, and the destructor (§19
...
4) must care about the two alternatives
...
Consequently, it would be a waste to allocate space for both ch and space in a String object
...
3)
...
3
...
All members of an anonymous union are allocated in the same memory, starting at the
same address
...
It is
the programmer’s job to make sure that they are never misused
...
That is
done by looking at sz<=short_max
...


Section 19
...
3
...
3
...
1 Ancillary Functions
In addition to functions intended for general use, I found that my code became cleaner when I provided three ancillary functions as ‘‘building blocks’’ to help me with the somewhat tricky representation and to minimize code replication
...
However, I made them private members because they don’t represent
operations that are generally useful and safe to use
...
Ancillary functions can lead to less
duplication of code, better design, and improved maintainability
...
4
return p;
}

// expand into free store

This function does not access the String representation, so I did not make it a member
...
sz<=short_max) {
// copy *this
memcpy(this,&x,sizeof(x));
// §43
...
ptr,x
...
sz;
space = 0;
}
}

Any necessary cleanup of the target String is the task of callers of copy_from(); copy_from() unconditionally overwrites its target
...
5) to copy the bytes of the
source into the target
...
It should be used
only where there are no objects with constructors or destructors in the copied memory because
memcpy() knows nothing about types
...

The corresponding function for move operations is:
void String::move_from(String& x)
{
if (x
...
5

566

Special Operators

else {
ptr = x
...
sz;
space = x
...
ptr = x
...
sz = 0;
x
...
However, it does not leave its argument owning any free store
...


19
...
4 Member Functions
The default constructor defines a String to be empty:
String::String()
: sz{0}, ptr{ch}
{
ch[0] = 0;
}

// default constructor : x{""}
// ptr points to elements, ch is an initial location (§19
...
3)
// terminating 0

Given copy_from() and move_from(), the constructors, moves, and assignments are fairly simple to
implement
...
In either case, the characters are copied from the argument string into the memory managed
by String
...
6
...
I don’t know if that would be worthwhile
...
3
...
In addition, it has to delete any free store owned by the target and make sure it does not get
into trouble with self-assignment (e
...
, s=s):
String& String::operator=(const String& x)
{
if (this==&x) return ∗this;
// deal with self-assignment
char∗ p = (short_maxcopy_from(x);
delete[] p;
return ∗this;
}

The String move assignment deletes its target’s free store (if there is any) and then moves:
String& String::operator=(String&& x)
{
if (this==&x) return ∗this;
if (short_maxmove_from(x);
return ∗this;
}

// deal with self-assignment (x = move(x) is insanity)
// delete target
// does not throw

It is logically possible to move a source into itself (e
...
, s=std::move(s)), so again we have to protect
against self-assignment (however unlikely)
...
If more space is needed, expand() is
called to allocate that space and move the old characters into the new space
...
Once enough space is available, it is trivial to put the new character c into it and to add the terminating 0
...
Of all the String implementation that took
the longest to get right: its a messy little calculation prone to off-by-one errors
...
’’
All String members take care not to modify a new representation before they are certain that a
new one can be put in place
...
In fact, the String members provide the strong exception guarantee (§13
...

If you don’t like the kind of fiddly code presented as part of the implementation of String, simply use std::string
...
Stronger: writing a string class, a vector class, or a map is
an excellent exercise
...


19
...
5 Helper Functions
To complete class String, I provide a set of useful functions, stream I/O, support for range-for loops,
comparison, and concatenation
...
In particular, << just prints the characters without added formatting, and >> skips initial whitespace before
reading until it finds terminating whitespace (or the end of the stream):
ostream& operator<<(ostream& os, const String& s)
{
return os << s
...
3
...
4
...
1)
char ch = ' ';
while(is
...
3
...
size()!=b
...
size(); ++i)
if (a[i]!=b[i])
return false;
return true;
}
bool operator!=(const String& a, const String& b)
{
return !(a==b);
}

Adding <, etc
...

To support the range-for loop, we need begin() and end() (§9
...
1)
...
c_str();
}

// C-string-style access

char∗ end(String& x)
{
return x
...
size();
}
const char∗ begin(const String& x)
{
return x
...
c_str()+x
...
Should I have provided a member += that added a Cstyle string to the end? The standard-library string does, but without it, concatenation with a C-style
string still works
...
My guess is that I could provide a
more efficient String::operator+=(const char∗), but I have no idea if the added performance would be
worthwhile in real-world code
...
Being able to do something is not by itself a good reason for doing it
...

Adding _s as a string literal suffix meaning String is trivial:
String operator"" _s(const char∗ p, size_t)
{
return String{p};
}

We can now write:
void f(const char∗);
void f(const String&);

// C-style string
// our string

void g()
{
f("Madden's");
f("Christopher's"_s);
}

// f(const char*)
// f(const String&);

19
...
6 Using Our String
The main program simply exercises the String operators a bit:
int main()
{
String s ("abcdefghij");
cout << s << '\n';
s += 'k';
s += 'l';
s += 'm';
s += 'n';
cout << s << '\n';

Section 19
...
6

Using Our String

571

String s2 = "Hell";
s2 += " and high water";
cout << s2 << '\n';
String s3 = "qwerty";
s3 = s3;
String s4 ="the quick brown fox jumped over the lazy dog";
s4 = s4;
cout << s3 << " " << s4 << "\n";
cout << s + "
...
") + "Horsefeathers\n";
String buf;
while (cin>>buf && buf!="quit")
cout << buf << " " << buf
...
capacity() << '\n';
}

This String lacks many features that you might consider important or even essential
...


19
...

[2] The function is in the scope of the class
...

By declaring a member function static (§16
...
12), we can give it the first two properties only
...
That is, a function
declared friend is granted access to the implementation of a class just like a member function but is
otherwise independent of that class
...
Naturally, Vector
and Matrix hide their respective representations and provide a complete set of operations for manipulating objects of their type
...

Also, we don’t really want to provide low-level access functions to allow every user to both read
and write the complete representation of both Matrix and Vector
...

friend Vector operator∗(const Matrix&, const Vector&);
};

572

Special Operators

Chapter 19

class Matrix {
Vector v[rc_max];
//
...
That would allow
sophisticated implementation techniques, but a simple implementation would be:
Vector operator∗(const Matrix& m, const Vector& v)
{
Vector r;
for (int i = 0; i!=rc_max; i++) {
// r[i] = m[i] * v;
r
...
v[i] += m
...
v[j] ∗ v
...
Like a member function, a friend function is explicitly declared in the declaration of the class of which it is a friend
...

A member function of one class can be the friend of another
...

int∗ next();
};
class List {
friend int∗ List_iterator::next();
//
...
For example:
class List {
friend class List_iterator;
//
...

Declaring a class a friend grants access to every function of that class
...
In this, a friend class declaration differs from the declaration of a member function
and a friend function
...

It is possible to make a template argument a friend:

Section 19
...

};

Often, there is a choice between making a class a member (a nested class) or a nonmember friend
(§18
...
1)
...
4
...
Scopes outside the innermost enclosing
namespace scope are not considered for a name first declared as a friend (§iso
...
3
...
2)
...
x = 1; } // OK: friend of C
} // namespace N
class C4 { };
void f4() { N::C x; x
...
2
...
For example:
void f(Matrix& m)
{
invert(m);
}

// Matrix’s friend invert()

574

Special Operators

Chapter 19

Thus, a friend function should be explicitly declared in an enclosing scope or take an argument of
its class or a class derived from that
...
For example:
// no f() in this scope
class X {
friend void f();
// useless
friend void h(const X&); // can be found through its argument
};
void g(const X& x)
{
f();
// no f() in scope
h(x);
// X’s friend h()
}

19
...
2 Friends and Members
When should we use a friend function, and when is a member function the better choice for specifying an operation? First, we try to minimize the number of functions that access the representation of a class and try to make the set of access functions as appropriate as possible
...
Some operations must be members – for example, constructors, destructors, and
virtual functions (§3
...
3, §17
...
5) – but typically there is a choice
...

Consider a class X supplying alternative ways of presenting an operation:
class X {
//
...
or −> (but see §19
...
3)
...
m1(); // error: X(99)
...
m2(); // error: X(99)
...
4
...
7)
...

Operators that modify an operand (e
...
, =, ∗=, and ++) are most naturally defined as members for
user-defined types
...
This is often the case for the functions implementing operators
that do not require lvalue operands when applied to fundamental types (e
...
, +, −, and ||)
...
Consequently, binary
operators are the most common source of friend functions
...
In some cases, the programmer
may have a preference for one call syntax over another
...
inv()
...

All other things considered equal, implement operations that need direct access to a representation as member functions:
• It is not possible to know if someone someday will define a conversion operator
...

• Expressions in the body of a member can be noticeably shorter than the equivalent expressions in a global function; a nonmember function must use an explicit argument, whereas
the member can use this implicitly
...

• If we have defined a member f() and we later feel the need for a nonmember f(x), we can
simply define it to mean x
...

Conversely, operations that do not need direct access to a representation are often best represented
as nonmember functions, possibly in a namespace that makes their relationship with the class
explicit (§18
...
6)
...
5 Advice
[1]
[2]

Use operator[]() for subscripting and for selection based on a single value; §19
...
1
...
2
...

[3] Use operator−>() to dereference ‘‘smart pointers’’; §19
...
3
...
2
...

[5] Define the global operator new() and operator delete() only if you really have to; §19
...
5
...
2
...

[7] Use user-defined literals to mimic conventional notation; §19
...
6
...
2
...

[9] For nonspecialized uses, prefer the standard string (Chapter 36) to the result of your own
exercises; §19
...

[10] Use a friend function if you need a nonmember function to have access to the representation
of a class (e
...
, to improve notation or to access the representation of two classes); §19
...

[11] Prefer member functions to friend functions for granting access to the implementation of a
class; §19
...
2
...

– William Occam










Introduction
Derived Classes
Member Functions; Constructors and Destructors
Class Hierarchies
Type Fields; Virtual Functions; Explicit Qualification; Override Control; using Base Members; Return Type Relaxation
Abstract Classes
Access Control
protected Members; Access to Base Classes; using-Declarations and Access Control
Pointers to Members
Pointers to Function Members; Pointers to Data Members; Base and Derived Members
Advice

20
...
In addition, it borrowed the
design idea that classes should be used to model concepts in the programmer’s and the application’s
world
...
Conversely,
using the language features in support of design ideas distinguishes effective use of C++
...

A concept (idea, notion, etc
...
It coexists with related concepts and
derives much of its power from relationships with other concepts
...
Soon you’ll have introduced the notions of wheels, engines, drivers, pedestrians, trucks,
ambulances, roads, oil, speeding tickets, motels, etc
...
However, we can’t express arbitrary relationships directly in a programming language
...
To
be useful, our classes should be more narrowly defined than our everyday concepts – and more precise
...
For example, the concepts of a circle and a triangle are related in that they are both shapes; that is, they have the concept
of a shape in common
...
In that case, the common class, here Shape, is referred to as the base class or superclass and classes derived from that, here Circle and Triangle, are referred to as derived classes or
subclasses
...
This chapter is an exploration of the implications of
this simple idea, which is the basis for what is commonly called object-oriented programming
...
In
contrast, the uniform use of classes not related by inheritance provided by templates (§3
...

The discussion of class hierarchies is organized into three chapters:
• Derived Classes (Chapter 20): This chapter introduces the basic language features supporting object-oriented programming
...

• Class Hierarchies (Chapter 21): This chapter focuses on the use of base and derived classes
to effectively organize code around the notion of class hierarchies
...

• Run-time Type Identification (Chapter 22): This chapter describes the techniques for explicitly navigating class hierarchies
...

A brief introduction to the basic idea of hierarchical organization of types can be found in Chapter
3: base and derived classes (§3
...
2) and virtual functions (§3
...
3)
...


20
...
Such a program might have
a data structure like this:

Section 20
...

};

Next, we might try to define a manager:
struct Manager {
Employee emp;
// manager’s employee record
list group; // people managed
short level;
//
...
This may be obvious to a human reader – especially a careful reader – but there is nothing
that tells the compiler and other tools that Manager is also an Employee
...
In particular, one cannot put
a Manager onto a list of Employees without writing special code
...
However,
both solutions are inelegant and can be quite obscure
...

};

The Manager is derived from Employee, and conversely, Employee is a base class for Manager
...
) in addition to its
own members (group, level, etc
...
A base class is sometimes called a superclass and a derived class a subclass
...
A derived class is typically larger (and never
smaller) than its base class in the sense that it holds more data and provides more functions
...
For example:
Employee:

Manager:
first_name
family_name

first_name
family_name


...

group
level


...
The space required is just the space required
by the members
...
For example, we can now create a list of
Employees, some of whom are Managers:
void f(Manager m1, Employee e1)
{
list elist {&m1,&e1);
//
...
Similarly, a Manager& can be used as an Employee&
...
In general, if a class Derived has a public base class
(§20
...
The opposite conversion, from Base∗ to Derived∗, must be explicit
...
The opposite is not true
...
2
...
2

Derived Classes

581

Using a class as a base is equivalent to defining an (unnamed) object of that class
...
2
...

};

20
...
1 Member Functions
Simple data structures, such as Employee and Manager, are really not that interesting and often not
particularly useful
...
For example:
class Employee {
public:
void print() const;
string full_name() const { return first_name + ' ' + middle_initial + ' ' + family_name; }
//
...

};
class Manager : public Employee {
public:
void print() const;
//
...
5) – members of a base
class as if they were declared in the derived class itself
...

}

However, a derived class cannot access private members of a base class:
void Manager::print() const
{
cout << " name is " << family_name << '\n';
//
...


Manager::print()

// error!

will not compile because

family_name

is not accessible to

582

Derived Classes

Chapter 20

This comes as a surprise to some, but consider the alternative: that a member function of a
derived class could access the private members of its base class
...
Furthermore, one could no longer find all uses of a
private name by looking at the functions declared as members and friends of that class
...
This is, at best,
tedious and often impractical
...
5)
...
For example:
void Manager::print() const
{
Employee::print(); // print Employee information
cout << level;
// print Manager-specific information
//
...
Such reuse of names is typical
...


20
...
2 Constructors and Destructors
As usual, constructors and destructors are as essential:
• Objects are constructed from the bottom up (base before member and member before
derived) and destroyed top-down (derived before member and member before base);
§17
...
3
...
4
...

• Typically, destructors in a hierarchy need to be virtual; §17
...
5
...
5
...
4
...
4
...
In source text, definitions of base
classes must occur before the definitions of their derived classes
...
Furthermore, we tend to draw trees
with the root on top
...
2
...
g
...
g
...
We build from the roots (base classes) toward the leaves (derived classes)
...
3 Class Hierarchies
A derived class can itself be a base class
...
*/ };
class Manager : public Employee { /*
...
*/ };

Such a set of related classes is traditionally called a class hierarchy
...
For example:
class Temporary { /*
...
*/ };
class Temp : public Temporary, public Assistant { /*
...
*/ };

or graphically:
Temporary

Employee

Assistant

Manager

Temp

Consultant

Director

Thus, as is explained in detail in §21
...


20
...
1 Type Fields
To use derived classes as more than a convenient shorthand in declarations, we must solve the following problem: Given a pointer of type Base∗, to which derived type does the object pointed to
really belong? There are four fundamental solutions:
[1] Ensure that only objects of a single type are pointed to (§3
...

[2] Place a type field in the base class for the functions to inspect
...
2, §22
...

[4] Use virtual functions (§3
...
3, §20
...
2)
...
3
...
2), solution 1 relies on more knowledge about the types
involved than is available to the compiler
...
g
...
Solutions [2], [3], and [4] can be used to build heterogeneous lists, that is, lists of (pointers
to) objects of several different types
...


584

Derived Classes

Chapter 20

Solution [4] is a special type-safe variation of solution [2]
...

Let us first examine the simple type-field solution to see why it is typically best avoided
...

};
struct Manager : public Employee {
Manager() { type = man; }
list group; // people managed
short level;
//
...

break;
case Employee::man:
{
cout << e−>family_name << '\t' << e−>department << '\n';
//
...

break;
}
}
}

and use it to print a list of Employees, like this:

Section 20
...
1

Type Fields

585

void print_list(const list& elist)
{
for (auto x : elist)
print_employee(x);
}

This works fine, especially in a small program maintained by a single person
...
This problem is usually made worse because functions such as
print_employee() are often organized to take advantage of the commonality of the classes involved:
void print_employee(const Employee∗ e)
{
cout << e−>family_name << '\t' << e−>department << '\n';
//
...

}
}

Finding all such tests on the type field buried in a large function that handles many derived classes
can be difficult
...

Furthermore, any addition of a new kind of Employee involves a change to all the key functions in a
system – the ones containing the tests on the type field
...
This implies the need to
access critical source code and the resulting necessary overhead of testing the affected code
...

In other words, use of a type field is an error-prone technique that leads to maintenance problems
...
Each function using a type
field must know about the representation and other details of the implementation of every class
derived from the one containing the type field
...
The common base thus becomes the repository of all kinds
of ‘‘useful information
...
In a large class hierarchy, accessible (not private)
data in a common base class becomes the ‘‘global variables’’ of the hierarchy
...


20
...
2 Virtual Functions
Virtual functions overcome the problems with the type-field solution by allowing the programmer
to declare functions in a base class that can be redefined in each derived class
...

For example:

586

Derived Classes

Chapter 20

class Employee {
public:
Employee(const string& name, int dept);
virtual void print() const;
//
...

};

The keyword virtual indicates that print() can act as an interface to the print() function defined in this
class and print() functions defined in classes derived from it
...

To allow a virtual function declaration to act as an interface to functions defined in derived
classes, the argument types specified for a function in a derived class cannot differ from the argument types declared in the base, and only very slight changes are allowed for the return type
(§20
...
6)
...

A virtual function must be defined for the class in which it is first declared (unless it is declared
to be a pure virtual function; see §20
...
For example:
void Employee::print() const
{
cout << family_name << '\t' << department << '\n';
//
...
When deriving a class,
simply provide an appropriate function if it is needed
...

private:
list group;
short level;
//
...

}

Section 20
...
2

Virtual Functions

587

A function from a derived class with the same name and the same set of argument types as a virtual
function in a base is said to override the base class version of the virtual function
...
3
...

Except where we explicitly say which version of a virtual function is called (as in the call
Employee::print()), the overriding function is chosen as the most appropriate for the object for which
it is called
...

The global function print_employee() (§20
...
1) is now unnecessary because the print() member
functions have taken its place
...
For example:
int main()
{
Employee e {"Brown",1234};
Manager m {"Smith",1234,2};
print_list({&e,&m});
}

produced:
Smith 1234
level 2
Brown 1234

Note that this will work even if print_list() was written and compiled before the specific derived
class Manager was even conceived of! This is a key aspect of classes
...

Getting ‘‘the right’’ behavior from Employee’s functions independently of exactly what kind of
Employee is actually used is called polymorphism
...
To get runtime polymorphic behavior in C++, the member functions called must be virtual and objects must be manipulated through
pointers or references
...

By default, a function that overrides a virtual function itself becomes virtual
...
I don’t recommend repeating virtual
...
3
...
1)
...
In a
typical implementation, the space taken is just enough to hold a pointer (§3
...
3): the usual implementation technique is for the compiler to convert the name of a virtual function into an index into

588

Derived Classes

Chapter 20

a table of pointers to functions
...
Each class with virtual functions has its own vtbl identifying its virtual functions
...


vtbl:
Employee::print()

...

group
level

...


The functions in the vtbl allow the object to be used correctly even when the size of the object and
the layout of its data are unknown to the caller
...
This virtual call
mechanism can be made almost as efficient as the ‘‘normal function call’’ mechanism (within
25%), so efficiency concerns should not deter anyone from using a virtual function where an ordinary function call would be acceptably efficient
...
You pay this overhead only for
objects of a class with a virtual function
...
Had you chosen to use the alternative type-field solution, a comparable amount of space would have been needed for the type field
...
4)
...


20
...
3 Explicit Qualification
Calling a function using the scope resolution operator, ::, as is done in Manager::print() ensures that
the virtual mechanism is not used:
void Manager::print() const
{
Employee::print(); // not a virtual call
cout << "\tlevel " << level << '\n';
//
...
3
...
The use of a qualified name has
another desirable effect
...
This provides the programmer with an efficient
way to handle some important special cases in which one virtual function calls another for the same
object
...
Because the type of the object is determined in the call of Manager::print(), it need not be dynamically determined again for the resulting
call of Employee::print()
...
3
...

That’s a simple and effective rule
...
Consider:
struct B0 {
void f(int) const;
virtual void g(double);
};
struct B1 : B0 { /*
...
*/ };
struct B3 : B2 { /*
...
*/ };
struct B5 : B4 { /*
...
B5 have many members each and are scattered over many header files
...
3
...

• D::g() doesn’t have the same argument type as B0::g(), so if it overrides anything it’s not the
virtual function B0::g()
...

• There is no function called h() in B0, if D::h() overrides anything, it is not a function from B0
...

I didn’t show you what was in B1
...
I personally don’t (redundantly) use virtual for a function
that’s meant to override
...
However, for larger hierarchies more specific controls are useful:
• virtual: The function may be overridden (§20
...
2)
...
4)
...
3
...
1)
...
3
...
2)
...
3
...

A compiler can warn against inconsistent use of explicit override controls
...


20
...
4
...
B5 do not provide relevant functions), all three declarations give errors
...

Using override is a bit verbose but clarifies the programmer’s intent
...
For example:
void f(int) const noexcept override; // OK (if there is a suitable f() to override)
override void f(int) const noexcept; // syntax error
void f(int) override const noexcept; // syntax error

And yes, it’s illogical that virtual is a prefix and override is a suffix
...

An override specifier is not part of the type of a function and cannot be repeated in an out-ofclass definition
...

}

// error : override out of class

void g()
{
//
...
That is, override has

Section 20
...
4
...
For example:
int override = 7;
struct Dx : Base {
int override;
int f() override
{
return override + ::override;
}
};

Don’t indulge in such cleverness; it complicates maintenance
...
The other contextual keyword is
final (§20
...
4
...


20
...
4
...

We use virtual for functions we want writers of derived classes to be able to define or redefine
...
e
...
The standard library is full
of examples of this
...
’’ For example, we can imagine
an abstract syntax tree for a language where all language constructs have been defined as concrete
node classes derived from a few interfaces
...
In that case, we might want to prevent our users from overriding virtual functions
because the only thing such overrides could do would be to change the semantics of our language
...
For example:
struct Node { // interface class
virtual Type type() = 0;
//
...

};

592

Derived Classes

Chapter 20

In a realistic class hierarchy, there would be several intermediate classes between the general interface (here, Node) and the derived class representing a specific language construct (here, If_statement)
...
After using final for a member function, it can no longer be overridden and an attempt to do
so is an error
...

};

We can make every virtual member function of a class final; just add final after the class name
...

};
class Modified_for_statement : public For_statement {
Type type() override;
//
...
There are people who use final to try to gain performance – after all, a nonvirtual function is faster than a virtual one (by maybe 25% on a modern implementation) and offers
greater opportunities for inlining (§12
...
5)
...
Do some serious measurements before claiming efficiency improvements
...
That is, use final to
reflect a semantic need
...
For example:
class Derived : public Base {
void f() final;
// OK if Base has a virtual f()
void g() final;
// OK if Base has a virtual g()
//
...

}

// error: final out of class

Section 20
...
4
...

}

final

593

// OK

Like override (§20
...
4
...
That is, final has a special meaning in a few
contexts but can be used as an ordinary identifier elsewhere
...
The only reason that final is a contextual keyword, rather than an ordinary keyword, is that there exist a significant amount of code
that has used final as an ordinary identifier for decades
...
3
...
1)
...
3
...
3
...
For example:
struct Base {
void f(int);
};
struct Derived : Base {
void f(double);
};
void use(Derived d)
{
d
...
f(1);
// call Base::f(int)
}

This can surprise people, and sometimes we want overloading to ensure that the best matching
member function is used
...
For example:
struct D2 : Base {
using Base::f;
void f(double);
};

// bring all fs from Base into D2

594

Derived Classes

void use2(D2 d)
{
d
...
f(1);
}

Chapter 20

// call D2::f(int), that is, Base::f(int)
// call Base::f(int)

This is a simple consequence of a class also being considered a namespace (§16
...

Several using-declarations can bring in names from multiple base classes
...
f(1);
// call D::f(int), that is, B1::f(int)
d
...
f(1
...
3
...
1
...
5
...
We cannot use using-directives to bring all members of a base class into a
derived class
...
3
...
1 Inheriting Constructors
Say I want a vector that’s just like std::vector, but with guaranteed range checking
...
3
...
1

Inheriting Constructors

595

Unfortunately, we would soon find out that this definition is rather incomplete
...

That’s not an unreasonable rule: if a class adds data members to a base or requires a stricter
class invariant, it would be a disaster to inherit constructors
...

We solve the problem by simply saying that the constructors should be inherited:
template
struct Vector : std::vector {
using vector::vector;

// inherit constructors

T& operator=[](size_type i) { check(i); return this−>elem(i); }
const T& operator=(size_type i) const { check(i); return this−>elem(i); }
void check(size_type i) { if (this−>size()};
Vector v { 1, 2, 3, 5, 8 };

// OK: use initializer-list constructor from std::vector

This use of using is exactly equivalent to its use for ordinary functions (§14
...
5, §20
...
5)
...
x is not initialized
// error: D1 has no default constructor

The reason that D1::s is initialized and D1::x is not is that the inheriting constructor is equivalent to
a constructor that simply initializes the base
...
4
...
x is zero
}

Most often it is best to avoid being clever and restrict the use of inheriting constructors to the simple cases where no data members are added
...
3
...
That is, if the original return type was B∗, then the return type of
the overriding function may be D∗, provided B is a public base of D
...
This is sometimes called the covariant return rule
...
2
...
In particular, there is not a similar relaxation of the rules for
argument types because that would lead to type violations
...
In addition to the operations for manipulating expressions, the base class Expr would provide facilities for making new
expression objects of the various expression types:
class Expr {
public:
Expr();
// default constructor
Expr(const Expr&);
// copy constructor
virtual Expr∗ new_expr() =0;
virtual Expr∗ clone() =0;
//
...
Both will return an object of some specific class derived from Expr
...

A derived class can override new_expr() and/or clone() to return an object of its own type:
class Cond : public Expr {
public:
Cond();
Cond(const Cond&);
Cond∗ new_expr() override { return new Cond(); }
Cond∗ clone() override { return new Cond(∗this); }
//
...
3
...
’’ For example:

Expr,

597

a user can create a new object of ‘‘just the same

void user(Expr∗ p)
{
Expr∗ p2 = p−>new_expr();
//
...

The return type of Cond::new_expr() and Cond::clone() is Cond∗ rather than Expr∗
...
Similarly, a derived class Addition would have
a clone() returning a Addition∗
...

}

If we use clone() for an Expr we only know that the result is an Expr∗:
void user3(Cond∗ pc, Expr∗ pe)
{
Cond∗ p1 = pc−>clone();
Cond∗ p2 = pe−>clone();
//
...
Each simply uses a constructor to create a suitable
object
...
Consequently,
a constructor cannot be virtual
...
In particular, it interacts with memory management routines in ways ordinary member functions don’t
...

Both of these restrictions can be circumvented by defining a function that calls a constructor
and returns a constructed object
...
The Ival_box_maker (§21
...
4) is an example of a class designed
specifically to do that
...
4 Abstract Classes
Many classes resemble class Employee in that they are useful as themselves, as interfaces for
derived classes, and as part of the implementation of derived classes
...
3
...
However, not all classes follow that pattern
...
A Shape makes

598

Derived Classes

Chapter 20

sense only as the base of some class derived from it
...

};

Trying to make a shape of this unspecified kind is silly but legal:
Shape s; // silly: ‘‘shapeless shape’’

It is silly because every operation on s will result in an error
...

A virtual function is ‘‘made pure’’ by the ‘‘pseudo initializer’’ = 0:
class Shape {
// abstract class
public:
virtual void rotate(int) = 0;
virtual void draw() const = 0;
virtual bool is_closed() const = 0;
//
...
Consequently, it is usually important for an abstract class to have
a virtual destructor (§3
...
4, §21
...
2)
...

An abstract class can be used only as an interface to other classes
...
*/ };
class Circle : public Shape {
public:
void rotate(int) override { }
void draw() const override;
bool is_closed() const override { return true; }
Circle(Point p, int r);
private:
Point center;
int radius;
};

Section 20
...
This allows us to build implementations in stages:
class Polygon : public Shape {
// abstract class
public:
bool is_closed() const override { return true; }
//
...

};
Polygon b {p1,p2,p3,p4};

// error : declaration of object of abstract class Polygon

is still abstract because we did not override draw() and rotate()
...

};
Irregular_polygon poly {p1,p2,p3,p4};

// assume that p1
...
For example, an
operating system might hide the details of its device drivers behind an abstract class:
class Character_device {
public:
virtual int open(int opt) = 0;
virtual int close(int opt) = 0;
virtual int read(char∗ p, int n) = 0;
virtual int write(const char∗ p, int n) = 0;
virtual int ioctl(int
...

The design style supported by abstract classes is called interface inheritance in contrast to the
implementation inheritance supported by base classes with state and/or defined member functions
...
That is, we can define and use base classes with
both state and pure virtual functions
...

With the introduction of abstract classes, we have the basic facilities for writing a complete program in a modular fashion using classes as building blocks
...
5 Access Control
A member of a class can be private, protected, or public:
• If it is private, its name can be used only by member functions and friends of the class in
which it is declared
...
4)
...

This reflects the view that there are three kinds of functions accessing a class: functions implementing the class (its friends and members), functions implementing a derived class (the derived class’s
friends and members), and other functions
...
What a name refers to does not affect the control
of its use
...
, as well as
private data members
...
A list is nonintrusive if it does not require modification to its elements
(e
...
, by requiring element types to have link fields)
...

private:
struct Link { T val; Link∗ next; };
struct Chunk {
enum { chunk_size = 15 };
Link v[chunk_size];
Chunk∗ next;
};

Section 20
...
allocate a new chunk and place its Links on the free list
...
However, because
the return type of get_free() is mentioned before the name List::get_free() is mentioned, the full
name List::Link must be used instead of the abbreviation Link
...
1
...

}

Nonmember functions (except friends) do not have such access:
template
void would_be_meddler(List∗ p)
{
List::Link∗ q = 0;
//
...

if (List::Chunk::chunk_size > 31) {
//
...
2
...

The obvious alternative to using a member type is to place the type in the surrounding namespace
...

};

is implicitly parameterized with List’s parameter T
...

If a member type does not depend on all the template class’s parameters, the nonmember version can be preferable; see §23
...
6
...

If the nested class is not generally useful by itself and the enclosing class needs access to its
representation, declaring the member class a friend (§19
...
2) may be a good idea:
Link

template class List;
template
class Link3 {
friend class List;
T val;
Link3∗ next;
};

// only List can access Link

Section 20
...

};

A compiler may reorder sections of a class with separate access specifiers (§8
...
6)
...
Such reordering could
come as a surprise to the programmer and is implementation-dependent, so don’t use multiple
access specifiers for data members without good reason
...
5
...
For example, we may provide an (efficient)
unchecked access function for derived class implementers and (safe) checked access for others
...
For example:
class Buffer {
public:
char& operator[](int i);
//
...

};

// checked access

// unchecked access

class Circular_buffer : public Buffer {
public:
void reallocate(char∗ p, int s);
//
...

for (int i=0; i!=old_sz; ++i)
p[i] = access(i);
// no redundant checking
//
...
access(3) = 'c';
}

Chapter 20

// OK (checked)
// error : Buffer ::access() is protected

For another example, see Window_with_border in §21
...
5
...

A derived class can access a base class’s protected members only for objects of its own type:
class Buffer {
protected:
char a[128];
//
...

};
class Circular_buffer : public Buffer {
//
...


20
...
1
...
3) well
...
’’ The members and friends that implement the operations on the class operate
on the class objects on behalf of these users
...

Members declared protected are far more open to abuse than members declared private
...
Placing significant amounts of
data in a common class for all derived classes to use leaves that data open to corruption
...
Thus, protected data becomes a software maintenance problem
...
In my experience, there have always been alternatives to placing significant
amounts of information in a common base class for derived classes to use directly
...
5
...
1

Use of protected Members

605

However, none of these objections are significant for protected member functions; protected is a
fine way of specifying operations for use in derived classes
...
2
...
Had the implementation class been private in this example, further derivation would
have been infeasible
...


20
...
2 Access to Base Classes
Like a member, a base class can be declared private, protected, or public
...
*/ };
class Y : protected B { /*
...
*/ };

The different access specifiers serve different design needs:
• public derivation makes the derived class a subtype of its base
...
This is the most common form of derivation
...
For example, B is an implementation detail of Z
...
3
is a good example
...
Like
private derivation, protected derivation is used to represent implementation details
...
2
...

The access specifier for a base class can be left out
...
For example:
class XX : B { /*
...
*/ };

// B is a private base
// B is a public base

People expect base classes to be public (that is, to express a subtype relationship), so the absence of
an access specifier for a base is likely to be surprising for a class but not for a struct
...
Consider a
class D derived from a base class B:
• If B is a private base, its public and protected members can be used only by member functions and friends of D
...

• If B is a protected base, its public and protected members can be used only by member functions and friends of D and by member functions and friends of classes derived from D
...

• If B is a public base, its public members can be used by any function
...
Any function can convert a D∗ to a B∗
...
5)
...
For an example, see Ival_slider in §21
...
2
...
5
...
1 Multiple Inheritance and Access Control
If the name of a base class can be reached through multiple paths in a multiple-inheritance lattice
(§21
...
For example:
struct B {
int m;
static int sm;
//
...
*/ } ;
class D2 : public virtual B { /*
...
*/ };
D12∗ pd = new D12;
B∗ pb = pd;
// OK: accessible through D1
int i1 = pd−>m;
// OK: accessible through D1

If a single entity is reachable through several paths, we can still refer to it without ambiguity
...
*/ } ;
class X2 : public B { /*
...
*/ };
XX∗ pxx = new XX;
int i1 = pxx−>m;
int i2 = pxx−>sm;

// error, ambiguous: XX::X1::B::m or XX::X2::B::m?
// OK: there is only one B::sm in an XX (sm is a static member)

20
...
3 using-Declarations and Access Control
A using-declaration (§14
...
2, §20
...
5) cannot be used to gain access to additional information
...
On the other hand,
once access is available, it can be granted to other users
...
5
...
For example:
class BB : private B {
public:
using B::b;
using B::c;
};

// give access to B::b and B::c, but not B::a

See also §20
...
5
...
6 Pointers to Members
A pointer to member is an offset-like construct that allows a programmer to indirectly refer to a
member of a class
...
∗ are arguably the most specialized and least used C++
operators
...
Using −>∗, we can
access a member that (conceptually) has its name stored in a pointer to member, ptom: p−>∗ptom
...
In both cases, p must be a
pointer to an object of an appropriate class
...
A null pointer
(e
...
, nullptr) can be assigned to a pointer to member and then represents ‘‘no member
...
6
...
For example, many ‘‘object-oriented’’ user interfaces define a set of requests to which every
object represented on the screen should be prepared to respond
...
Consider a simple variant of this idea:
class Std_interface {
public:
virtual void start() = 0;
virtual void suspend() = 0;
virtual void resume() = 0;
virtual void quit() = 0;
virtual void full_size() = 0;
virtual void small() = 0;
virtual ˜Std_interface() {}
};

The exact meaning of each operation is defined by the object on which it is invoked
...

Ideally, such intermediate layers of software should not have to know anything about the individual
operations such as resume() and full_size()
...
Consequently, such intermediate layers simply transmit
data representing the operation to be invoked from the source of the request to its recipient
...
For
example, to invoke suspend() we could send the string "suspend"
...

Often, that seems indirect and tedious
...
For example, 2 might be used to mean suspend()
...
We still have to write
code to determine that 2 means suspend() and to invoke suspend()
...
Consider
Std_interface
...
I also need a pointer or reference
to the object I want to suspend
...
A variable of type ‘‘pointer to member
of class X’’ is declared using a declarator of the form X::∗
...
However, please note how the X::∗ declarator matches the traditional ∗ declarator exactly
...
The operators −>∗ and
...
For example, p−>∗m binds m to the object
pointed to by p, and obj
...
The result can be used in accordance with m’s
type
...
∗ operation for later use
...
Just like ordinary pointers to functions, pointers to member functions are used when we need to refer to a function without having to know its name
...
It is more like an offset into a structure or an index into an array, but of course an
implementation takes into account the differences between data members, virtual functions, nonvirtual functions, etc
...

The p−>∗s() call can be represented graphically like this:
vtbl:
p

X::start
s:

X::suspend

Section 20
...
1

Pointers to Function Members

609

Because a pointer to a virtual member (s in this example) is a kind of offset, it does not depend on
an object’s location in memory
...
Like pointers to ordinary
functions, pointers to non-virtual member functions cannot be exchanged between address spaces
...
For example,
when we call suspend() through a pointer to function, we get the right suspend() for the object to
which the pointer to function is applied
...

When writing an interpreter, we might use pointers to members to invoke functions presented as
strings:
map variable;
map operation;
void call_member(string var, string oper)
{
(variable[var]−>∗operation[oper])(); // var
...
For example:

static

member is simply

class Task {
//
...
6
...


20
...
2 Pointers to Data Members
Naturally, the notion of pointer to member applies to data members and to member functions with
arguments and return types
...
print(1);
(z1
...
∗pm = "nv1 ";
p−>∗pm = "nv2 ";
z2
...


20
...
3 Base and Derived Members
A derived class has at least the members that it inherits from its base classes
...

This implies that we can safely assign a pointer to a member of a base class to a pointer to a member of a derived class, but not the other way around
...

For example:
class Text : public Std_interface {
public:
void start();
void suspend();
//
...
In fact, both rules exist to preserve the fundamental
guarantee that a pointer may never point to an object that doesn’t at least have the properties that
the pointer promises
...
Consequently, they do not have the member
Text::print with which we tried to initialize pmi
...


Section 20
...
7 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]

Avoid type fields; §20
...
1
...
3
...

Use abstract classes to focus design on the provision of clean interfaces; §20
...

Use override to make overriding explicit in large class hierarchies; §20
...
4
...

Use final only sparingly; §20
...
4
...

Use abstract classes to specify interfaces; §20
...

Use abstract classes to keep implementation details out of interfaces; §20
...

A class with a virtual function should have a virtual destructor; §20
...

An abstract class typically doesn’t need a constructor; §20
...

Prefer private members for implementation details; §20
...

Prefer public members for interfaces; §20
...

Use protected members only carefully when really needed; §20
...
1
...

Don’t declare data members protected; §20
...
1
...


611

This page intentionally left blank

21
Class Hierarchies
Abstraction is selective ignorance
...
Virtual Bases
Advice

21
...
The examples are taken from user-interface design, but I avoid the topic of event-driven programming as
commonly used for graphical user interface (GUI) systems
...
For an understanding of GUI, have a look at one of the many C++ GUI libraries
...
2 Design of Class Hierarchies
Consider a simple design problem: Provide a way for a program (‘‘an application’’) to get an integer value from a user
...
To insulate our program
from this variety, and also to get a chance to explore the possible design choices, let us start by
defining our program’s model of this simple input operation
...
A program can ask an Ival_box for its value and ask it to prompt the user if
necessary
...

The general approach is to build a ‘‘virtual user-interface system’’ for the application to use
...
It can be
implemented on a wide variety of systems to ensure the portability of application code
...
I chose this
approach because it is general, because it allows me to demonstrate a variety of techniques and
design tradeoffs, because those techniques are also the ones used to build ‘‘real’’ user-interface systems, and – most important – because these techniques are applicable to problems far beyond the
narrow domain of interface systems
...


21
...
1 Implementation Inheritance
Our first solution is a class hierarchy using implementation inheritance (as is commonly found in
older programs)
...
In addition, we declare
the data needed to implement the basic notion:
class Ival_box {
protected:
int val;
int low, high;
bool changed {false};
// changed by user using set_value()
public:
Ival_box(int ll, int hh) :val{ll}, low{ll}, high{hh} { }
virtual int get_value() { changed = false; return val; }
virtual void set_value(int i) { changed = true; val = i; }
virtual void reset_value(int i) { changed = false; val = i; }
virtual void prompt() { }
virtual bool was_changed() const { return changed; }
virtual ˜Ival_box() {};
};

// for application
// for user
// for application

Section 21
...
1

Implementation Inheritance

615

The default implementation of the functions is pretty sloppy and is provided here primarily to illustrate the intended semantics
...

A programmer might use these ‘‘ival classes’’ like this:
void interact(Ival_box∗ pb)
{
pb−>prompt(); // aler t user
//
...
new value; do something
...
do something else
...
get());

// Ival_slider derived from Ival_box

unique_ptr p2 {new Ival_dial{1,12}};
interact(p2
...
That
way, the application doesn’t have to know about the potentially large number of variants of the
Ival_box concept
...
This isolates users from changes in the implementations of the
derived classes
...

I use unique_ptr (§5
...
1, §34
...
1) to avoid forgetting to delete the ival_boxes
...
Maybe the
program really does wait for the user in get_value() (e
...
, using a get() on a future; §5
...
5
...
Such
decisions are crucial in the design of user-interface systems
...
The design techniques described here and the language facilities that support them
are not specific to user interfaces
...

The different kinds of Ival_boxes are defined as classes derived from Ival_box
...
graphics stuff to define what the slider looks like, etc
...
Thus,
Ival_slider::get_value() can deposit a value in Ival_box::val
...
5)
...
These could
include Ival_dial, which lets you select a value by turning a knob; Flashing_ival_slider, which flashes
when you ask it to prompt(); and Popup_ival_slider, which responds to prompt() by appearing in
some prominent place, thus making it hard for the user to ignore
...
So, if we use the system from ‘‘Big
Bucks Inc
...
, classes a kind of BBwidget
...

In that way, all our classes inherit all the properties of a BBwidget
...
, according to the standard set by the BBwidget system
...
*/ }; // rewritten to use BBwidget
class Ival_slider : public Ival_box { /*
...
*/ };
class Flashing_ival_slider : public Ival_slider { /*
...
*/ };

or graphically:
BBwidget

Ival_box

Ival_slider

Popup_ival_slider

Ival_dial

Flashing_ival_slider

21
...
1
...
However, there are some awkward details that could lead us to look for alternative designs
...
This is not quite right (even if this style is common in real-world systems)
...
Deriving Ival_box from BBwidget elevated an implementation detail to a
first-level design decision
...
For example, using the environment defined by ‘‘Big
Bucks Inc
...
However,
what if we also wanted to have implementations of our Ival_boxes for systems from ‘‘Imperial

Section 21
...
1
...
*/ };
class Ival_box : public CWwidget { /*
...
*/ };
class Ival_box : public LSwindow { /*
...

In reality, we are unlikely to find a simple, coherent, two-letter prefix scheme
...
But that does not
affect our class hierarchy design discussion, so to simplify I ignore naming and namespace issues
...
That data
is, of course, an implementation detail that also crept into our Ival_box interface
...
For example, an Ival_slider doesn’t need the
value stored specifically
...
In general, keeping two related, but different, sets of data is asking for trouble
...
Also, experience shows that novice programmers tend to mess with protected data in ways that are unnecessary and that cause maintenance problems
...
Better still, data should be in the derived classes, where it can be defined to match
requirements exactly and cannot complicate the life of unrelated derived classes
...

Deriving from BBwidget gives the benefit of making the facilities provided by BBwidget available to users of Ival_box
...
In particular, the way
most C++ implementations work implies that a change in the size of a base class requires a recompilation of all derived classes
...
This could happen either because two systems somehow share a
screen or because our program needs to communicate with users on different systems
...


21
...
2 Interface Inheritance
So, let’s start again and build a new class hierarchy that solves the problems presented in the critique of the traditional hierarchy:
[1] The user-interface system should be an implementation detail that is hidden from users
who don’t want to know about it
...

[3] No recompilation of code using the Ival_box family of classes should be required after a
change of the user-interface system
...


618

Class Hierarchies

Chapter 21

Several alternative approaches can be taken to achieve this
...

First, I specify class Ival_box as a pure interface:
class Ival_box {
public:
virtual int get_value() = 0;
virtual void set_value(int i) = 0;
virtual void reset_value(int i) = 0;
virtual void prompt() = 0;
virtual bool was_changed() const = 0;
virtual ˜Ival_box() { }
};

This is much cleaner than the original declaration of Ival_box
...
Gone, too, is the constructor, since there is no
data for it to initialize
...

The definition of Ival_slider might look like this:
class Ival_slider : public Ival_box, protected BBwidget {
public:
Ival_slider(int,int);
˜Ival_slider() override;
int get_value() override;
void set_value(int i) override;
//
...
functions overriding BBwidget virtual functions
// e
...
, BBwidget::draw(), BBwidget::mouse1hit()
...
data needed for slider
...
It also inherits from BBwidget which provides it with the
means of doing so
...
Since BBwidget is only an implementation aid, it is derived using protected (§20
...
2)
...
The
interface provided by Ival_slider is the one inherited from Ival_box, plus what Ival_slider explicitly
declares
...
I used explicit override
because this ‘‘widget hierarchy’’ is exactly the kind of large, complicated hierachy where being
explicit can help minimize confusion
...
3)
...
Therefore, it must be
derived directly or indirectly from both
...
2
...
1, deriving Ival_slider indirectly from
BBwidget by making BBwidget a base of Ival_box is possible, but doing so has undesirable side

Section 21
...
2

Interface Inheritance

619

effects
...
Representing the window by a BBwidget∗ member in Ival_box leads to a completely different design with a separate set of
tradeoffs
...

However, the use of one base class for implementation details and another for interface (the abstract
class) is common to all languages supporting inheritance and compile-time checked interfaces
...

Interestingly, this declaration of Ival_slider allows application code to be written exactly as
before
...

Many classes require some form of cleanup for an object before it goes away
...
We ensure proper cleanup by defining a virtual destructor Ival_box::˜Ival_box() in the
base and overriding it suitably in derived classes
...

delete p;
}

The delete operator explicitly destroys the object pointed to by p
...

The Ival_box hierarchy can now be defined like this:
class Ival_box { /*
...
*/ };
class Ival_dial
: public Ival_box, protected BBwidget { /*
...
*/ };
class Popup_ival_slider
: public Ival_slider { /*
...
5
...
General users cannot access the
protected bases because they are (correctly) considered part of the implementation
...
2
...

However, it still fails to solve the version control problem:
class Ival_box { /*
...
*/ }; // for BB
class Ival_slider
: public Ival_box, protected CWwidget { /*
...


There is no way of having the Ival_slider for BBwidgets coexist with the Ival_slider for CWwidgets,
even if the two user-interface systems could themselves coexist
...
*/ };
class BB_ival_slider
: public Ival_box, protected BBwidget { /*
...
*/ };
//
...
*/ };
class Ival_slider
: public Ival_box { /*
...
*/ };
class CW_ival_slider
: public Ival_slider, protected CWwidget { /*
...


or graphically:
Ival_box

BBwidget

Ival_slider

BB_ival_slider

CWwidget

CW_ival_slider

Section 21
...
3

Alternative Implementations

621

Usually, we can do better yet by utilizing more specific classes in the implementation hierarchy
...
’’ system has a slider class, we can derive our Ival_slider directly
from the BBslider:
class BB_ival_slider
: public Ival_slider, protected BBslider { /*
...
*/ };

or graphically:
BBwidget

Ival_box

CWwidget

BBslider

Ival_slider

CWslider

BB_ival_slider

CW_ival_slider

This improvement becomes significant where – as is not uncommon – our abstractions are not too
different from the ones provided by the system used for implementation
...
Derivation from general base classes, such
as BBwidget, is then done only rarely
...
*/ };
class Ival_slider
: public Ival_box { /*
...
*/ };
class Flashing_ival_slider
: public Ival_slider { /*
...
*/ };

followed by the implementations of this hierarchy for various graphical user interface systems,
expressed as derived classes:
class BB_ival_slider
: public Ival_slider, protected BBslider { /*
...
*/ };
class BB_popup_ival_slider
: public Popup_ival_slider, protected BBslider { /*
...
*/ };
//
...


21
...
3
...
In the latter design, the windows class
is the root of a tree
...
From the application’s point of view, these designs
are equivalent in the strong sense that almost all code works unchanged and in the same way in the
two cases
...
For example, we would not need to rewrite interact() from §21
...
1 if we switched from one class hierarchy to the other
...
However, in the abstract class design, almost all
user code is protected against changes to the implementation hierarchy and requires no recompilation after such a change
...
In addition, users of the abstract class hierarchy
are in less danger of being locked into a proprietary implementation than are users of a classical
hierarchy
...

The logical conclusion of this line of thought is a system represented to users as a hierarchy of
abstract classes and implemented by a classical hierarchy
...
2
...
1)
...
2
...
1)
...
2
...
2
...
Further, should the derived interfaces evolve to provide more facilities than plain Ival_box, then most of an application can be written using the Ival_box, Ival_slider, etc
...
However, the creation of objects must be done
using implementation-specific names such as CW_ival_dial and BB_flashing_ival_slider
...

As usual, the solution is to introduce an indirection
...
A simple
one is to introduce an abstract class to represent the set of creation operations:
class Ival_maker {
public:
virtual Ival_dial∗ dial(int, int) =0;
virtual Popup_ival_slider∗ popup_slider(int, int) =0;
//
...
Such a class is sometimes called a factory, and
its functions are (somewhat misleadingly) sometimes called virtual constructors (§20
...
6)
...

};
class LS_maker : public Ival_maker {
// make LS versions
public:
Ival_dial∗ dial(int, int) override;
Popup_ival_slider∗ popup_slider(int, int) override;
//
...
For example:
Ival_dial∗ BB_maker::dial(int a, int b)
{
return new BB_ival_dial(a,b);
}
Ival_dial∗ LS_maker::dial(int a, int b)
{
return new LS_ival_dial(a,b);
}

Given an Ival_maker, a user can now create objects without having to know exactly which userinterface system is used
...
dial(0,99)};
//
...
In particular, we cannot override
the base class functions that represent the interface with different arguments in different derived
classes
...


21
...
1, inheritance aims to provide one of two benefits:
• Shared interfaces: leading to less replication of code using classes and making such code
more uniform
...

• Shared implementation: leading to less code and more uniform implementation code
...

A class can combine aspects of these two styles
...


21
...
1 Multiple Interfaces
An abstract class (e
...
, Ival_box; §21
...
2) is the obvious way to represent an interface
...
The resolution of potential ambiguities is discussed in §21
...
3,
§21
...
4, and §21
...
5
...
The key observation is that
a class without mutable state can be replicated if necessary or shared if that is desired
...


21
...
2 Multiple Implementation Classes
Consider a simulation of bodies orbiting the Earth in which orbiting objects are represented as
object of class Satellite
...
, and provide operations for orbital calculations, modifying attributes, etc
...
3
...
These kinds of satellites would be objects of classes derived from Satellite
...

Now assume that I want to display the results of these simulations graphically and that I had
available a graphics system that used the (not uncommon) strategy of deriving objects to be displayed from a common base class holding graphical information
...
For generality, simplicity, and to hide the
details of the actual graphics system, I will refer to the class providing graphical (or in fact alternatively nongraphical) output Display
...

};

or graphically:
Satellite

Displayed

Comm_sat

In addition to whatever operations are defined specifically for a Comm_sat, the union of operations
on Satellite and Displayed can be applied
...
draw();
// Displayed::draw()
Pos p = s
...
transmit();
// Comm_sat::transmit()
}

Similarly, a Comm_sat can be passed to a function that expects a
expects Displayed
...
Virtual functions work as usual
...

};

Chapter 21

// center of gravity

class Displayed {
public:
virtual void draw() = 0;
//
...

};

This ensures that Comm_sat::center() and Displayed::draw() will be called for a Comm_sat treated as
a Comm_sat and a Displayed, respectively
...
Alternatively, I
could have defined Comm_sat to have a Satellite∗ member and a Displayed∗ member and let its constructor set up the proper connections
...
However,
the system that inspired this example was built on the idea of a Satellite class with virtual functions
and a (separately designed) Displayed class with virtual functions
...
In particular, you had to override Satellite virtual member functions and Displayed virtual member functions to specify the behavior of your own
objects
...
Workarounds can be painful and hard to maintain
...
Basically, it saves the programmer from writing a lot of forwarding functions (to compensate for the fact that we can only override functions defined in bases)
...
However, a technique doesn’t have to be clever to be useful
...
This is typically more flexible and leads to systems that are easier to
evolve
...
g
...

Note that with single inheritance (only), the programmer’s choices for implementing the classes
Displayed, Satellite, and Comm_sat would be limited
...
Either alternative
involves a loss of flexibility
...
3
...
There really was – and maybe there still is – a program constructed along the
lines used to describe multiple implementation inheritance here
...
In fact, Satellite was derived from
an early notion of a concurrent task
...

lite

21
...
3 Ambiguity Resolution
Two base classes may have member functions with the same name
...

};
class Displayed {
public:
virtual Debug_info get_debug();
//
...
This can be done simply by
qualifying a member name by its class name:
void f(Comm_sat& cs)
{
Debug_info di = cs
...
Satellite::get_debug();
di = cs
...

};

A function declared in a derived class overrides all functions of the same name and type in its base
classes
...
The ideal for virtual is for a

628

Class Hierarchies

Chapter 21

call to have the same effect independently of which interface was used to find the function
(§20
...
2)
...
A qualified name, such as Telstar::draw, can refer to
a draw declared either in Telstar or in one of its base classes
...
own stuff
...

};

// finds Displayed::draw

or graphically:
Satellite

Displayed

Comm_sat

Telstar

If Comm_sat::draw doesn’t resolve to a draw declared in Comm_sat, the compiler recursively looks
in its base classes; that is, it looks for Satellite::draw and Displayed::draw, and if necessary looks in
their base classes
...
Otherwise,
Comm_sat::draw is either not found or is ambiguous
...

I could have said Displayed::draw(), but now the code would be subtly broken if someone added
a Comm_sat::draw(); it is generally better to refer to a direct base class than to an indirect base class
...
Had I said
Satellite::draw(), the result would have been an error because the draw is over on the Displayed
branch of the class hierarchy
...
Getting an exact match of names, return types, argument types, and
semantics by accident is extremely unlikely
...

We might originally have been presented with two classes SimObj and Widget that we could not
modify, didn’t exactly provide what we needed, and where they did provide what we needed, did so
through incompatible interfaces
...
3
...

};
class Displayed : public Widget {
// map Widget facilities to something easier to use to display Satellite simulation results
public:
virtual Debug_info get_debug();
// read Widget data and compose Debug_info
//
...
Consider the classical (but mostly hypothetical/theoretical)
example of a class of a draw() member function in a video game involving cowboys:
class Window {
public:
void draw();
//
...

};

// pull gun from holster

class Cowboy_window : public Cowboy, public Window {
//
...
There is no direct language solution to this (exotic) problem, but adding intermediate classes will do:
struct WWindow : Window {
using Window::Window;
virtual void win_draw() = 0;
void draw() override final { win_draw(); }
};

// inherit constructors
// force derived class to override
// display image

struct CCowboy : Cowboy{
using Cowboy::Cowboy;
virtual void cow_draw() = 0;
void draw() override final { cow_draw(); }
};

// inherit constructors
// force derived class to override
// pull gun from holster

class Cowboy_window : public CCowboy, public WWindow {
public:
void cow_draw() override;
void win_draw() override;
//
...
I find that fairly typical
...
3
...
When a class can have multiple base classes, a class can appear multiple times in the resulting hierarchy
...
g
...
For example:

Section 21
...
4

Repeated Use of a Base Class

631

class Transmitter : public Storable {
public:
void write() override;
//
...

};
class Radio : public Transmitter, public Receiver {
public:
string get_file() override;
void read() override;
void write() override;
//
...

[2] A Radio object has one subobject of class Storable (shared by Transmitter and Receiver)
...
Unless you state otherwise,
you get one copy for each time you mention a class as a base
...
Typically, an overriding function calls its base class versions and then does the work specific
to the derived class:
void Radio::write()
{
Transmitter::write();
Receiver::write();
//
...

}

Casting from a replicated base class to a derived class is discussed in §22
...
For a technique for
overriding each of the write() functions with separate functions from derived classes, see §21
...
3
...
3
...
The reason for that is simply that Storable is an abstract class
providing a pure interface
...
This is the simplest case and
the one that offers the best separation of interface and implementation concerns
...

What if Storable did hold data and it was important that it should not be replicated? For example, we might define Storable to hold the name of the file to be used for storing the object:
class Storable {
public:
Storable(const string& s);
virtual void read() = 0;
virtual void write() = 0;
virtual ˜Storable();
protected:
string file_name;

// store in file named s

Storable(const Storable&) = delete;
Storable& operator=(const Storable&) = delete;
};

Given this apparently minor change to Storable, we must change the design of Radio
...
Otherwise, we could get two parts of something
derived from Storable multiple times using different files
...
For example:
class Transmitter : public virtual Storable {
public:
void write() override;
//
...

};
class Radio : public Transmitter, public Receiver {
public:
void write() override;
//
...
3
...
3
...
In an inheritance graph, every base class of a
given name that is specified to be virtual will be represented by a single object of that class
...

Why would someone want to use a virtual base containing data? I can think of three obvious
ways for two classes in a class hierarchy to share data:
[1] Make the data nonlocal (outside the class as a global or namespace variable)
...

[3] Allocate an object somewhere and give each of the two classes a pointer
...
It breaks all notions of encapsulation and locality
...
However, for single inheritance
that solution makes useful data (and functions) ‘‘bubble up’’ to a common base class; often it ‘‘bubbles’’ all the way to the root of an inheritance tree
...
That is logically very similar to using nonlocal data and suffers from the same
problems
...

Option [3], sharing an object accessed through pointers, makes sense
...
That is roughly what constructors do to implement a virtual base
...
However, if you do need sharing within a general class hierarchy, you basically have a choice between using a virtual base and laboriously constructing your own variants of
the idea
...
Expect a storage overhead of one word for each virtual base
...
3
...
1 Constructing Virtual Bases
Using virtual bases you can create complicated lattices
...
Furthermore, the constructor of a base (whether virtual or not)
is called before its derived classes
...
To avoid such chaos, the constructor of every virtual base is
invoked (implicitly or explicitly) from the constructor for the complete object (the constructor for
the most derived class)
...
For example:
struct V {
V(int i);
//
...

};

// default constructor

struct B : virtual V, virtual A {
B() :V{1} { /*
...

};
class C : virtual V {
public:
C(int i) : V{i} { /*
...

};

// must initialize base V

class D : virtual public B, virtual public C {
// implicitly gets the virtual base V from B and C
// implicitly gets virtual base A from B
public:
D() { /*
...
*/ };
// error : no default constructor for V
D(int i, int j) :V{i}, C{j} { /*
...

};

Note that D can and must provide an initializer for V
...
Knowledge of a virtual base and the obligation to initialize it ‘‘bubbles
up’’ to the most derived class
...
3
...
1

Constructing Virtual Bases

635

class
...
Thus, only the initializer provided by the most derived class is
used
...

In practice, this is not quite as localized as we would prefer
...
Unless we can simply
inherit D’s constructors (§20
...
5
...
That ought to encourage us not to
overuse virtual base classes
...
They are simply invoked
in reverse order of construction (§20
...
2)
...


21
...
5
...
This can be a problem when implementing a service that requires a base class function to be called exactly once for each call of a
derived function
...
For example, assume we
have a basic Window class that knows how to draw its contents:
class Window {
public:
// basic stuff
virtual void draw();
};

In addition, we have various ways of decorating a window and adding facilities:
class Window_with_border : public virtual Window {
// border stuff
protected:
void own_draw(); // display the border
public:
void draw() override;
};
class Window_with_menu : public virtual Window {
// menu stuff
protected:
void own_draw(); // display the menu
public:
void draw() override;
};

The own_draw() functions need not be virtual because they are meant to be called from within a virtual draw() function that ‘‘knows’’ the type of the object for which it was called
...
This is done independently of the kind of Window

void Window_with_border::draw()
{
Window::draw();
own_draw(); // display the border
}
void Window_with_menu::draw()
{
Window::draw();
own_draw(); // display the menu
}
void Clock::draw()
{
Window::draw();
Window_with_border::own_draw();
Window_with_menu::own_draw();
own_draw(); // display the clock face and hands
}

Note that a qualified call, such as Window::draw(), does not use the virtual call mechanism
...

Casting from a virtual base class to a derived class is discussed in §22
...


21
...
6 Replicated vs
...
Class BB_ival_slider (§21
...
3) is an example:

Section 21
...
6

Replicated vs
...
One base is a public abstract
class providing the interface, and the other is a protected concrete class providing implementation
‘‘details
...
5)
provided
...

For example, consider again the Ival_box classes from §21
...
1
...
2
...
Doing that allowed me to place
all implementation details in specific implementation classes
...

When using an abstract class (without any shared data) as an interface, we have a choice:
• Replicate the interface class (one object per mention in the class hierarchy)
...

Using Ival_slider as a virtual base gives us:
class BB_ival_slider
: public virtual Ival_slider, protected BBslider { /*
...
*/ };
class BB_popup_ival_slider
: public virtual Popup_ival_slider, protected BB_ival_slider { /*
...

However, we also have this alternative using replicated Ival_slider objects:
class BB_ival_slider
: public Ival_slider, protected BBslider { /*
...
*/ };
class BB_popup_ival_slider
: public Popup_ival_slider, protected BB_ival_slider { /*
...

There are logical differences, though
...
2)
...

How do we choose between virtual base classes and replicated base classes for our interfaces?
Most often, of course, we don’t get a choice because we have to conform to an existing design
...
2
...
For example:
Popup_ival_slider∗ popup_slider_factory(args)
{
//
...

}

No explicit conversion is needed to get from an implementation (here,
direct interfaces (here, Popup_ival_slider)
...
3
...
1 Overriding Virtual Base Functions
A derived class can override a virtual function of its direct or indirect virtual base class
...
In that
way, several derived classes can contribute implementations to the interface presented by a virtual
base class
...
In that
case, Window_with_border might override set_color() as part of controlling the color scheme, and
Window_with_menu might override prompt() as part of its control of user interactions:

Section 21
...
6
...

virtual void set_color(Color) = 0;
virtual void prompt() = 0;
};

639

// set background color

class Window_with_border : public virtual Window {
//
...

void prompt() override;
// control user interactions
};
class My_window : public Window_with_menu, public Window_with_border {
//
...
That is, one function
must override all others
...

void prompt() override; // don’t leave user interactions to base
};

or graphically:
Window { set_color(), prompt() }

Window_with_border { set_color() }

Window_with_menu { prompt() }

My_window { prompt() }

If two classes override a base class function, but neither overrides the other, the class hierarchy is
an error
...
Or, using implementation terminology, no
virtual function table can be constructed because a call to that function on the complete object
would be ambiguous
...
3
...
As with Radio,
such a conflict is resolved by adding an overriding function to the most derived class
...


640

Class Hierarchies

Chapter 21

21
...
2
...

Avoid date members in base classes intended as interfaces; §21
...
1
...

Use abstract classes to express interfaces; §21
...
2
...
2
...

Use override to make overriding explicit in large class hierarchies; §21
...
2
...
2
...

Use base classes with data members to support implementation inheritance; §21
...
2
...
3
...
3
...
3
...


22
Run-Time Type Information
Premature optimization
is the root of all evil
...

– Jon Bentley









Introduction
Class Hierarchy Navigation
dynamic cast; Multiple Inheritance; static_cast and dynamic_cast; Recovering an Interface
Double Dispatch and Visitors
Double Dispatch; Visitors
Construction and Destruction
Type Identification
Extended Type Information
Uses and Misuses of RTII
Advice

22
...
Such a class lattice is often called a
class hierarchy
...
In particular, the virtual call mechanism ensures that when
we call a function f() on an object, the same function is called whichever class in the hierarchy provided the declaration of f() used for the call and whichever class defined it
...


642

Run-Time Type Information

Chapter 22

22
...
2 would be to hand them to a system that controlled
a screen and have that system hand objects back to the application program whenever some activity
had occurred
...
Objects passed back and forth between the system and the application are commonly referred to as widgets or controls
...

From a language point of view, it is important that the system does not know about our Ival_boxes
...
This is necessary and proper
...

Recovering the ‘‘lost’’ type of an object requires us to somehow ask the object to reveal its type
...
Consequently, the most obvious and useful operation for inspecting the type of an object at
run time is a type conversion operation that returns a valid pointer if the object is of the expected
type and a null pointer if it isn’t
...
For example,
assume that ‘‘the system’’ invokes my_event_handler() with a pointer to a BBwindow, where an activity has occurred
...

int x = pb−>get_value(); // use the Ival_box
//
...
oops! cope with unexpected event
...
It is important to note what is not mentioned in this example: the actual type of the object
...
It is neither necessary nor desirable to make the actual type of the object explicit in this
interaction between ‘‘the system’’ and the application
...
In particular, a well-designed interface hides inessential details
...
2

Class Hierarchy Navigation

643

The arrows from pw and pb represent the pointers into the object passed, whereas the rest of the
arrows represent the inheritance relationships between the different parts of the object passed
...

Casting from a base class to a derived class is often called a downcast because of the convention
of drawing inheritance trees growing from the root down
...
A cast that goes from a base to a sibling class, like the cast from BBwindow to Ival_box, is called a crosscast
...
2
...
Consider first the pointer case:
dynamic_cast(p)

If p is of type T∗ or of a type D∗ where T is a base class of D, the result is exactly as if we had simply assigned p to a T∗
...

};
void f(BB_ival_slider∗ p)
{
Ival_slider∗ pi1 = p;
Ival_slider∗ pi2 = dynamic_cast(p);
BBslider∗ pbb1 = p;
BBslider∗ pbb2 = dynamic_cast(p);

// OK
// OK
// error : BBslider is a protected base
// OK: pbb2 becomes nullptr

}

This (the upcast) is the uninteresting case
...
Since a
dynamic_cast used as an upcast is exactly like a simple assignment, it implies no overhead and is
sensitive to its lexical context
...
In that case, dynamic_cast(p) looks at the object pointed
to by p (if any)
...
If the value of p is nullptr,
dynamic_cast(p) returns nullptr
...
It is possible to construct examples where the conversion fails and nullptr is
returned because the object pointed to by p has more than one subobject representing bases of type
T (§22
...

A dynamic_cast requires a pointer or a reference to a polymorphic type in order to do a downcast or a crosscast
...

};

// polymor phic base (Ival_slider has virtual functions)

class My_date : public Date {
//
...
A
typical implementation will attach a ‘‘type information object’’ (§22
...
2
...
For
example:
My_slider:


...


vtbl:

type_info:
"My_slider"

type_info:

bases
"Ival_slider"
My_slider::get_value()

The dashed arrow represents an offset that allows the start of the complete object to be found given
only a pointer to a polymorphic subobject
...
All that is involved are a few comparisons of type_info objects representing base classes;
no expensive lookups or string comparisons are needed
...

That is, if an object has no virtual functions, it cannot safely be manipulated without knowledge of
its exact type
...
If its type is known, we don’t need to use dynamic_cast
...
This allows us to wrap a concrete
type in a polymorphic type, say, for transmission through an object I/O system (§22
...
4), and then
‘‘unwrap’’ the concrete type later
...
2
...

}

A dynamic_cast to void∗ can be used to determine the address of the beginning of an object of polymorphic type
...
So, pb does not necessarily hold the same
address as pb2
...
There is no dynamic_cast from void∗ (because there would be no way of knowing
where to find the vptr; §22
...
3)
...
2
...
1 dynamic_cast to Reference
To get polymorphic behavior, an object must be manipulated through a pointer or a reference
...
That is neither feasible
nor desirable for references
...
Consequently, the result of a dynamic_cast of a pointer should
always be explicitly tested
...
use is
...
*p not a slider; handle alternatives
...
7
...
Consequently, dynamic_cast(r) of a reference r is not a question but an assertion: ‘‘The object referred
to by r is of type T
...
If the operand of a dynamic_cast to a reference isn’t of the
expected type, a bad_cast exception is thrown
...
use is
...
If a user wants to protect against
bad casts to references, a suitable handler must be provided
...
4
...
1
//
...

Explicit tests against nullptr can easily be accidentally omitted
...


22
...
2 Multiple Inheritance
When only single inheritance is used, a class and its base classes constitute a tree rooted in a single
base class
...
When multiple inheritance is used, there is no
single root
...
However, if a class appears more than
once in a hierarchy, we must be a bit careful when we refer to the object or objects that represent
that class
...

However, once a nontrivial hierarchy has been constructed, we sometimes need to navigate it to
find a specific class to use
...
3
...

• Sometimes, we want to obtain a pointer to a subobject of a hierarchy given a pointer to
another, for example, to get a pointer to the complete derived class object from a pointer to a
base (a downcast; §22
...
1) or to get a pointer to a base class object from a pointer to another
base (a crosscast; §22
...
4)
...
To illustrate the mechanisms available and the rules that guide them, consider a
lattice containing both a replicated base and a virtual base:

Section 22
...
2

Multiple Inheritance

647

class Component
: public virtual Storable { /*
...
*/ };
class Transmitter
: public Component { /*
...
*/ };

or graphically:
Storable

Component

Component

Receiver

Transmitter

Radio

Here, a
Storable

Radio object has two subobjects of class Component
...
There is simply no way of

knowing which Component the programmer wanted:
void h1(Radio& r)
{
Storable∗ ps = &r; // a Radio has a unique Storable
//
...

}

// pc = 0; a Radio has two Components

In general – and typically – a programmer (and a compiler looking at a single translation unit) does
not know the complete class lattice
...

For example, a programmer might know only about the Transmitter part of a Radio and write:
void h2(Storable∗ ps)
// ps might or might not point to a Component
{
if (Component∗ pc = dynamic_cast(ps)) {
// we have a component!
}
else {
// it wasn’t a Component
}
}

The ambiguity for a pointer to a Radio object is not in general detectable at compile time
...
For ordinary bases,
there is always a unique subobject of a given cast (or none) when downcasting (that is, toward a

648

Run-Time Type Information

Chapter 22

derived class; §22
...
The equivalent ambiguity for virtual bases occurs when upcasting (that is,
toward a base), but such ambiguities are caught at compile time
...
2
...
2
...
A static_cast (§11
...
2) does not examine the object it casts from, so it cannot:
void g(Radio& r)
{
Receiver∗ prec = &r;
// Receiver is an ordinary base of Radio
Radio∗ pr = static_cast(prec); // OK, unchecked
pr = dynamic_cast(prec);
// OK, run-time checked
Storable∗ ps = &r;
pr = static_cast(ps);
pr = dynamic_cast(ps);

// Storable is a virtual base of Radio
// error : cannot cast from virtual base
// OK, run-time checked

}

The dynamic_cast requires a polymorphic operand because there is no information stored in a nonpolymorphic object that can be used to find the objects for which it represents a base
...
For objects of such types, only static type information will
be available
...

Why would anyone want to use a static_cast for class hierarchy navigation? There is a run-time
cost associated with the use of a dynamic_cast (§22
...
1)
...
This code relies on alternative ways of making sure that a cast is valid, so the checking done by dynamic_cast is seen as
redundant
...
5
...
Where possible, use the safer dynamic_cast
...
This implies
that dynamic_cast – which must look into an object to determine its type – cannot cast from a void∗
...
For example:
Radio∗ f1(void∗ p)
{
Storable∗ ps = static_cast(p);
return dynamic_cast(ps);
}

// trust the programmer

Both dynamic_cast and static_cast respect const and access controls
...
*/ };
void f2(Users∗ pu, const Receiver∗ pcr)
{
static_cast∗>(pu);
dynamic_cast∗>(pu);

// error : access violation
// error : access violation

Section 22
...
3

static_cast(pcr);
dynamic_cast(pcr);

static_cast

and dynamic_cast

649

// error : can’t cast away const
// error : can’t cast away const

Receiver∗ pr = const_cast(pcr); // OK
//
...
5
...
Even then, using the result is safe only
provided the object wasn’t originally declared const (or volatile) (§16
...
9)
...
2
...
2
...

As an example, consider a simple object I/O system
...
For example:
void user()
{
//
...

unique_ptr p {get_obj(ss)}; // read object from stream
if (auto sp = dynamic_cast(p
...

}
else {
// oops: non-shape in Shape file
}
}

The function user() deals with shapes exclusively through the abstract class Shape and can therefore
use every kind of shape
...

I used unique_ptr (§5
...
1, §34
...
1) so that I would not forget to delete the object allocated by get_obj()
...
Class Io_obj must be a polymorphic type to allow the user of get_obj() to use dynamic_cast
to recover the ‘‘true type’’ of a returned object
...
Assume that the data representing an object on an input
stream is prefixed by a string identifying the object’s class
...
For example:
using Pf = Io_obj∗(istream&);

// pointer to function returning an Io_obj*

map io_map;

// maps strings to creation functions

string get_word(istream& is);

// read a word from is; throw Read_error if the read failed

Io_obj∗ get_obj(istream& is)
{
string str = get_word(is);
if (auto f = io_map[str])
return f(is);
throw Unknown_class{};
}

// read initial word
// look up str to get function
// call function
// no match for str

The map called io_map holds pairs of name strings and functions that can construct objects of the
class with that name
...

};

However, it would be more interesting (and in many cases more realistic) to use an already defined
Shape (§3
...
4) unchanged:
struct Io_circle : Circle, Io_obj {
Io_circle(istream&);
// initialize from input stream
Io_circle∗ clone() const { return new Io_circle{∗this}; }
// use copy constructor
static Io_obj∗ new_circle(istream& is) { return new Io_circle{is}; } // for io_map
};

This is an example of how a class can be fitted into a hierarchy using an abstract class with less
foresight than would have been required to build it as a node class in the first place (§21
...
2)
...
The
new_circle() function is the one put into the io_map to make the class known to the object I/O system
...

};
io_map["Io_triangle"]=&Io_circle::new_triangle;

// somewhere

Section 22
...
4

Recovering an Interface

651

If the provision of the object I/O scaffolding becomes tedious, a template might help:
template
struct Io : T, Io_obj {
public:
Io(istream&);
Io∗ clone() const override { return new Io{∗this}; }
static Io∗ new_io(istream& is) { return new Io{is}; }
};

// initialize from input stream
// for io_map

Given this, we can define Io_circle:
using Io_circle = Io;

We still need to define Io::Io(istream&) explicitly, though, because it needs to know about the
details of Circle
...
The idea is that the transmission format for a type X is what is needed to construct an X using
one of X’s constructors
...

The Io template is an example of a way to fit concrete types into a class hierarchy by providing
a handle that is a node in that hierarchy
...
For example:
void f(io& ios)
{
Shape∗ ps = &ios;
//
...
open file assumed to hold shapes, and attach ss as an istream for that file
...
get())) {
sp−>draw();
// use the Shape
//
...
oops: cope with non-shape in Shape file
...
It is a blueprint for the ‘‘receiver end’’ of a
system for transmitting arbitrary objects across a communication channel in a type-safe manner
...

In general, the sender part of such an object I/O system will also use RTTI
...

};

To correctly write out the Shape pointed to by outline, we need to figure out which kind of Shape it
is
...
5)
...


Section 22
...
3 Double Dispatch and Visitors
Classical object-oriented programming is based on selecting a virtual function based on the
dynamic type (the type of the most derived class) of an object given only a pointer or a reference to
an interface (a base class)
...
In this, C++ resembles Simula and Smalltalk and more recent languages, such as Java and C#
...
Also, a virtual function must be a member function
...
This too can be a serious problem
...
3
...

§22
...
2 Visitors shows how to use double dispatch to add multiple functions to a class hierarchy with only a single additional virtual function in the hierarchy
...
In such cases, the actual type of an
object (e
...
, a vector element or a graph node) can only be known dynamically by (implicitly or
explicitly) inspecting the interface provided by a base class
...
3
...
For example:
void do_someting(Shape& s1, Shape& s2)
{
if (s1
...

}

We would like this to work for any two classes in the class hierarchy rooted in Shape, such as Circle
and Triangle
...
To simplify, I will leave out the calculation of
whether the two shapes actually intersect and just write the code skeleton for selecting the right
functions
...
intersect(∗this); }
bool Circle::intersect(const Circle&) const { cout <<"intersect(circle,circle)\n"; return true; }
bool Circle::intersect(const Triangle&) const { cout <<"intersect(circle,triangle)\n"; return true; }
bool Triangle::intersect(const Shape& s) const { return s
...
These need to handle a Shape& argument because that argument must refer to a derived
class
...

That done, we are in one of the four functions that can actually do an intersection calculation
...
first−>intersect(∗p
...
We get:
intersect(triangle,triangle)
intersect(triangle,circle)
intersect(circle,triangle)
intersect(circle,circle)

If you consider this elegant, you need to raise your standards, but it gets the task done
...
That is not acceptable in most
cases
...
Worst of all, each new
operation and each new derived class require a modification to every class in the hierarchy: this
double-dispatch technique is highly intrusive
...
3
...
That is possible [Pirkelbauer,2009], but not in C++11
...
It is not unusual to want an action, such as intersect(x,y), that depends on the types of
two (or more) operands
...
For example, finding the intersection of rectangles
is simple and efficient
...
For example:
class Shape {
public:
virtual Rectangle box() const = 0;
//
...

};
class Triangle : public Shape {
public:
Rectangle box() const override;
//
...
box(),s2
...
Many variants use precomputed values stored in objects to
speed up type identification (§27
...
2)
...
3
...

Consider how to apply two (or more) operations to every class in a class hierarchy
...
The operations are called visitors; here they are defined in

656

Run-Time Type Information

Chapter 22

classes derived from class Visitor
...
For this example, I use a hierarchy of Nodes that describe language
constructs, as is common in tools based on abstract syntax trees (ASTs):
class Visitor;
class Node {
public:
virtual void accept(Visitor&) = 0;
};
class Expr : public Node {
public:
void accept(Visitor&) override;
};
class Stmt : public Node {
public:
void accept(Visitor&) override;
};

So far, so good: the Node hierarchy simply provides a virtual function accept() that takes a Visitor&
argument representing what should be done to a Node of a given type
...

Now the Node’s accept() performs the double-dispatch trick and passes the Node itself to the Visitor’s accept():
void Expr::accept(Visitor& v) { v
...
accept(∗this); }

The Visitor declares a set of operations:
class Visitor {
public:
virtual void accept(Expr&) = 0;
virtual void accept(Stmt&) = 0;
};

We can then define sets of operations by deriving from Visitor and overriding its accept() functions
...
3
...
first−>accept(∗p
...
It is only mildly intrusive (the accept() function), and many variations on the basic idea are
used
...
For example,
an operation that needs access to multiple nodes of different types in a graph cannot be trivially
implemented as a visitor
...
Alternatives
exist, for example, [Solodkyy,2012], but not in plain C++11
...
g
...

At each element or node, a call of a virtual function can perform the desired operation, or some
optimization based on stored data can be applied (e
...
, see §27
...
2)
...
4 Construction and Destruction
A class object is more than simply a region of memory (§6
...
A class object is built from ‘‘raw
memory’’ by its constructors, and it reverts to ‘‘raw memory’’ as its destructors are executed
...
This order is necessary to ensure that an object is not accessed
before it has been initialized
...
2
...
The order of construction and destruction
is reflected in the rules for RTTI, exception handling (§13
...
3
...

It is unwise to rely on details of the order of construction and destruction, but you can observe
that order by calling virtual functions, dynamic_cast (§22
...
5) at a point where the
object isn’t complete
...
For example, if the constructor for Component in the hierarchy
from §22
...
2 calls a virtual function, it will invoke a version defined for Storable or Component, but
not one from Receiver, Transmitter, or Radio
...
Similarly, calling a virtual function from a destructor will reflect only what is still not
destroyed
...


658

Run-Time Type Information

Chapter 22

22
...
Importantly, it ensures that code written using it works correctly with classes derived from
those explicitly mentioned by the programmer
...

However, it is occasionally essential to know the exact type of an object
...
The typeid operator serves this purpose by yielding an object representing the type of its operand
...
2
...

• Given an expression as its operand, typeid(expr) returns a reference to a type_info that represents the type of the object denoted by the expr; the expr must refer to a completely defined
type (§8
...
2)
...

A typeid() can find the type of an object referred to by a reference or a pointer:
void f(Shape& r, Shape∗ p)
{
typeid(r);
// type of the object referred to by r
typeid(∗p);
// type of the object pointed to by p
typeid(p);
// type of the pointer, that is, Shape* (uncommon, except as a mistake)
}

If the operand of typeid() is a pointer or a reference of a polymorphic type with the value nullptr,
typeid() throws a std::bad_typeid
...

If the object denoted by a dereferenced pointer or a reference to a polymorphic type, the
type_info returned is that of the most derived class for the object, that is, the type used when the
object was defined
...

};
struct Non_poly { /*
...
*/ };
struct D2
: Non_poly { /*
...
5

Type Identification

659

void f(Non_poly& npr, Poly& pr)
{
cout << typeid(npr)
...
name() << '\n'; // name of Poly or a class derived from Poly
}
void g()
{
D1 d1;
D2 d2;
f(d2,d1); // writes "Non_poly D1"
f(∗static_cast(nullptr),∗static_cast(nullptr)); // oops!
}

That last call will print just Non_poly (because
bad_typeid
...
In particular, it allows type_ids to be used as
keys for ordered containers (such as map)
...
The hash_code() function allows type_ids be used as keys
for hash tables (such as unordered_map)
...
In fact,
where dynamically linked libraries are used, it can be hard for an implementation to avoid duplicate
type_info objects
...

We sometimes want to know the exact type of an object so as to perform some service on the
whole object (and not just on one of its bases)
...
In some cases, no common interface can be assumed
for every object manipulated, so the detour through the exact type becomes necessary (§22
...
1)
...
name();
}

The character representation of a class’s name is implementation-defined
...


22
...
1 Extended Type Information
A type_info object contains only minimal information
...

Consider how an implementation or a tool could make information about types available to
users at run time
...
I can put these descriptors into a map to allow user code to find the layout information:
#include
map layout_table;
void f(B∗ p)
{
Layout& x = layout_table[typeid(∗p)
...
use x
...


Someone else might provide a completely different kind of information:
unordered_map icon_table;

// §31
...
3
...
use i
...
5
...

The resulting data structure looks like this:

Section 22
...
1

Extended Type Information

661

icon_table:


...


icon
representation
of
type

Associating typeids with information without modifying system headers allows several people or
tools to associate different information with types independently of each other
...


22
...
Static (compile-time)
checking is safer, implies less overhead, and – where applicable – leads to better-structured programs
...
However, programmers sometimes overlook
these alternatives and use RTTI where it is unsuitable
...
rotate triangle
...
rotate square
...

}

Using dynamic_cast rather than typeid would improve this code only marginally
...

Unfortunately, this is not a strawman example; such code really does get written
...
This urge should usually
be resisted
...
2
...
3
...

Many examples of proper use of RTTI arise when some service code is expressed in terms of
one class and a user wants to add functionality through derivation
...
2 is

662

Run-Time Type Information

Chapter 22

an example of this
...
Even if the user is
willing to modify the base classes (e
...
, to add a virtual function), such modification may cause its
own problems
...
A use of RTTI to
implement a simple object I/O system can be found in §22
...
4
...
Consider:
// misuse of run-time type information:
class Object { // polymor phic
//
...

};
class Ship : public Object { /*
...

Object∗ p = c−>get();
// retrieve an Object from the container
if (Ship∗ q = dynamic_cast(p)) {
// run-time check that the Object is a Ship
return q;
}
else {
//
...

}
}

Here, class Object is an unnecessary implementation artifact
...
Problems of this kind are often better solved
by using container templates that hold only a single kind of pointer:
Ship∗ f(Ship∗ ps, vector& c)
{
c
...

return c
...
6

Uses and Misuses of RTTI

663

This style of code is less error-prone (better statically type checked) and less verbose than a pureObject-based alternative
...
In a template, a template argument T takes the place of Object and enables static type checking (§27
...


22
...
1
...
2
...
2
...

[4] Use dynamic_cast to a reference type when failure to find the required class is considered a
failure; §22
...
1
...

[5] Use dynamic_cast to a pointer type when failure to find the required class is considered a
valid alternative; §22
...
1
...

[6] Use double dispatch or the visitor pattern to express operations on two dynamic types (unless
you need an optimized lookup); §22
...
1
...
4
...
5
...

[9] Use typeid to find the type of an object (and not to find an interface to an object); §22
...

[10] Prefer virtual functions to repeated switch-statements based on typeid or dynamic_cast; §22
...


This page intentionally left blank

23
Templates
Your quote here
...
Stroustrup












Introduction and Overview
A Simple String Template
Defining a Template; Template Instantiation
Type Checking
Type Equivalence; Error Detection
Class Template Members
Data Members; Member Functions; Member Type Aliases; static Members; Member Types;
Member Templates; Friends
Function Templates
Function Template Arguments; Function Template Argument Deduction; Function Template
Overloading
Template Aliases
Source Code Organization
Linkage
Advice

23
...
4) in the form of programming
using types as parameters
...
Templates provide a straightforward way to
represent a wide range of general concepts and simple ways to combine them
...

A template depends only on the properties that it actually uses from its parameter types and
does not require types used as arguments to be explicitly related
...
Built-in types are acceptable and
very common as template arguments
...
3)
...
This makes the library chapters (Part IV) of this book a
rich source of examples of templates and programming techniques relying on them
...
The standard library requires a greater degree of
generality, flexibility, and efficiency than does most software
...
These techniques enable an implementer to hide
sophisticated implementations behind simple interfaces and to expose complexity to the user when
the user has a specific need for it
...
This chapter focuses on the most basic template facilities and fundamental programming techniques for using them:
§23
...

§23
...

§23
...

§23
...
How overloading is
resolved for function templates and ordinary functions
...
6 Template Aliases: Template aliases provide a powerful mechanism for hiding implementation details and cleaning up the notation used for templates
...
7 Source Code Organization: How to organize templates into source files
...
2 Algorithms and Lifting: An example of the basic technique for developing a generic
algorithm from concrete examples
...
3 Concepts: Introduces and discusses the fundamental notion of a concept, that is, a set of
requirements that a template can impose on its template arguments
...
4 Making Concepts Concrete: Presents techniques for using concepts expressed as compile-time predicates
...
2 Template Parameters and Arguments: What can be a template argument: types, values,
and templates
...

§25
...


Section 23
...
2 Template Instantiation: The rules for when and how a compiler generates specializations
from a template definition and how to specify them manually
...
3 Name Binding: The rules for determining to which entity a name used in a template definition refers
...
The emphasis is on how to use them in combination:
§27
...
How do we choose between them?
§27
...
4 Template Parameters as Base Classes: Presents techniques for composing interfaces and
data structures for type safety and performance
...
2 Type Functions: Functions that take types as arguments or return types as results
...
3 Compile-time Control Structures: How to express selection and recursion for type functions, and some rules of thumb for their use
...
4 Conditional Definition: enable_if: How to conditionally define functions and overload
templates using (almost) arbitrary predicates
...
5 A Compile-time List: Tuple: How to build and access lists with elements of (almost) arbitrary types
...
6 Variadic templates: How (in a statically type-safe manner) to define templates that take
arbitrary numbers of template arguments of arbitrary types
...
7 SI Units Example: This example uses simple metaprogramming techniques in combination with other programming techniques to provide a library for computations that are
(at compile time) checked for correct use of the meters, kilograms, and seconds system
of units
...
2 A Matrix Template: How to define an N-dimensional matrix with flexible and type-safe
initialization, subscription, and submatrices
...
3 Matrix Arithmetic Operations: How to provide simple arithmetic operations on an Ndimensional matrix
...
4 Matrix Implementation: Some useful implementation techniques
...
5 Solving Linear Equations: An example of simple matrix use
...
4
...
4
...


668

Templates

Chapter 23

23
...
A string is a class that holds characters and provides operations
such as subscripting, concatenation, and comparison that we usually associate with the notion of a
‘‘string
...
For example, strings of signed characters, of unsigned characters, of Chinese characters, of Greek characters,
etc
...
Thus, we want to represent the notion of ‘‘string’’ with minimal
dependence on a specific kind of character
...
3)
...
3 and making the character type a parameter:
template
class String {
public:
String();
explicit String(const C∗);
String(const String&);
String operator=(const String&);
//
...

private:
static const int short_max = 15;
int sz;
C∗ ptr;
// ptr points to sz Cs
};

// unchecked element access
// add c at end

// for the short string optimization

The template prefix specifies that a template is being declared and that a type argument C will be used in the declaration
...
The scope of C extends to the end of the declaration prefixed by template
...
In either case, C is a type name;
it need not be the name of a class
...
’’ If you think along those lines, you will note that C++ lacks a fully general mechanism
for specifying the required properties of a template parameter C
...
’’ where the ‘‘
...
In other words, C++ does not offer a
direct way to say what kind of type a template argument C is supposed to be (§24
...

The name of a class template followed by a type bracketed by < > is the name of a class (as
defined by the template) and can be used exactly like other class names
...
*/ };
String js;

// Japanese character

Section 23
...
3
...
For example, if we use the standardlibrary map and the String template, the word-counting example from §19
...
1 becomes:
int main() // count the occurrences of each word on input
{
map,int> m;
for (String buf; cin>>buf;)
++m[buf];
//
...

}

The version for our Japanese-character type Jchar would be:
int main() // count the occurrences of each word on input
{
map,int> m;
for (String buf; cin>>buf;)
++m[buf];
//
...

}

The standard library provides the template class basic_string that is similar to the templatized String
(§19
...
3)
...
3):
using string = std::basic_string;

This allows us to write the word-counting program like this:
int main() // count the occurrences of each word on input
{
map m;
for (string buf; cin>>buf;)
++m[buf];
//
...

}

In general, type aliases (§6
...
Also, we often prefer not to know the details of how a type is defined, and an alias
allows us to hide the fact that a type is generated from a template
...
2
...
Thus, use of a template does
not imply any run-time mechanisms beyond what is used for an equivalent ‘‘handwritten’’ class
...
2
...

In addition to class templates, C++ offers function templates (§3
...
2, §23
...
I will introduce
most of the ‘‘mechanics’’ of templates in the context of class templates and postpone detailed discussion of function templates to §23
...
A template is a specification of how to generate something

670

Templates

Chapter 23

given suitable template arguments; the language mechanisms for doing that generation (instantiation (§26
...
3)) don’t care much whether a class or a function is generated
...
Templates can also be defined as aliases (§23
...

There are people who make semantic distinctions between the terms class template and template class
...
Similarly, I consider function template interchangeable with template function
...
By doing so, we handle many design
problems and most of the code errors in the context of a concrete example
...
Later, we can deal with any problems that might arise from generalization without being distracted by more conventional errors
...
This also fits with the philosophy that a generic
component should be developed as a generalization of one or more concrete examples, rather than
simply being designed from first principles (§24
...

Members of a class template are declared and defined exactly as they would have been for a
non-template class
...
In
that case, its definition must be provided somewhere else, just as for non-template class members
(§16
...
1)
...
When such a member is defined outside its class, it must explicitly be
declared a template
...
add c to the end of this string
...
However,
that doesn’t affect the way we write the template code using the name
...

Just as there can be only one function defining a class member function in a program, there can
be only one function template defining a class template member function in a program
...
3) enables us to provide alternative implementations for a template given

Section 23
...
1

Defining a Template

671

specific template arguments
...
5
...

It is not possible to overload a class template name, so if a class template is declared in a scope,
no other entity can be declared there with the same name
...
*/ };
class String { /*
...
For
example, a type used as an argument to String must provide the usual copy operations (§17
...
2
...
Note that there is no requirement that different arguments for the same template parameter should be related by inheritance
...
2
...
5
...
3 (requirements on template arguments)
...
2
...
2)
...

In general, it is the implementation’s job – not the programmer’s – to ensure that specializations
of a template are generated for each template argument list used
...
Other member
functions are not used and will not be generated
...
Similarly, generated functions are ordinary functions that
obey all the usual rules for functions
...
Consequently, a certain amount of caution is in order to avoid flooding memory with
almost identical function definitions (§25
...
On the other hand, templates can be written to enable
otherwise unachievable quality of generated code
...
For
example, that is how simple operations on critical data structures (such as < in a sort() and + for
scalars in a matrix computation) are reduced to single machine instructions in heavily parameterized libraries
...
In particular, the code

672

Templates

Chapter 23

generated for a simple < or [] is often a single machine instruction, which is both much faster than
any function call and smaller than the code needed to invoke a function and receive its result
...
3 Type Checking
Template instantiation takes a template plus a set of template arguments and generates code from
them
...
Unfortunately, this flexibility also
implies complexity of type checking and difficulties for accurate reporting of type errors
...
This generated code may contain much that the
user of a template has never heard of (such as names of details of a template implementation) and
often happens uncomfortably late in the build process
...

The fundamental weakness of the template mechanism is that it is not possible to directly
express requirements on a template argument
...
Work is being done to make this possible in future versions of C++ (without loss of flexibility, without loss of run-time performance, and without significant increases in compile time [Sutton,2011]), but for now we will have to do without
...
Think of a set of requirements
on template arguments as a predicate
...
For example, Container>() and Container>() should be true whereas Container() and Container>()
should be false
...
A concept is not (yet) a language construct in
C++; it is a notion that we can use to reason about requirements on template arguments, use in
comments, and sometimes support with our own code (§24
...

For starters, think of a concept as a design tool: specify Container() as a set of comments saying what properties a type T must have for Container() to be true
...

• T must have a size() member function
...

Note that this list is incomplete (e
...
, what does [] take as an argument and what does it return?)
and fails to address most semantic issues (e
...
, what does [] actually do?)
...
3

Type Checking

673

and catch obvious errors
...
I will return to the design of concepts (§24
...
4), and give an example of a set of useful concepts (§24
...
2)
...

Dennis Ritchie famously said, ‘‘C is a strongly typed, weakly checked language
...


23
...
1 Type Equivalence
Given a template, we can generate types by supplying template arguments
...
2
...
However, what does ‘‘the same’’ mean in this context? Aliases do not introduce new
types, so String and String are the same type as String
...
2
...

The compiler can evaluate constant expressions (§10
...

Types generated from a single template by different template arguments are different types
...
For example,
assume that a Circle is a kind of Shape:
Shape∗ p {new Circle(p,100)};
vector∗ q {new vector{}};
vector vs {vector{}};
vector vs {vector{}};

// Circle* converts to Shape*
// error : no vector* to vector* conversion
// error : no vector to vector conversion
// error : no vector to vector conversion

Had such conversions been allowed, type errors would have resulted (§27
...
1)
...
2
...


674

Templates

Chapter 23

23
...
2 Error Detection
A template is defined and then later used in combination with a set of template arguments
...
For example:
template
struct Link {
Link∗ pre;
Link∗ suc
T val;
};

// syntax error: missing semicolon

template
class List {
Link∗ head;
public:
List() :head{7} { }
List(const T& t) : head{new Link{0,o,t}} { }
//
...

Users generally prefer early detection, but not all ‘‘simple’’ errors are easy to detect
...

• A simple type error: Independently of what the template parameter is, a pointer cannot be
initialized by the integer 7
...

A name used in a template definition must either be in scope or in some reasonably obvious way
depend on a template parameter (§26
...
The most common and obvious ways of depending on a
template parameter T are to explicitly use the name T, to use a member of a T, and to take an argument of type T
...

For example:
class Rec {
string name;
string address;
};

Section 23
...
2

Error Detection

675

void f(const List& li, const List& lr)
{
li
...
print_all();
}

The li
...
print_all() gives a type error because there is no << output
operator defined for Rec
...
That point is called the
first point of instantiation (§26
...
3)
...
Independently of when checking is done, the same set of rules is
checked
...


23
...
4
...
4
...
6
• static members (function and data); §23
...
4
• Member types (e
...
, a member class); §23
...
5
• Member templates (e
...
, a member class template); §23
...
6
...
4
...

The rules for class template members are those for their generated classes
...


23
...
1 Data Members
As for an ‘‘ordinary class,’’ a class template can have data members of any type
...
4
...
2
...
For example:
template
struct X {
int m1 = 7;
T m2;
X(const T& x) :m2{x} { }
};
X xi {9};
X xs {"Rapperswil"};

Non-static data members can be const, but unfortunately not constexpr
...
4
...
For example:
template
struct X {
void mf1() { /*
...
*/ }

// defined in-class

// defined out of class

Similarly, a member function of a template can be virtual or not
...
4
...
2)
...
4
...
5), play a major role in the
design of class templates
...
For example, we specify a container’s iterator and element types as aliases:
template
class Vector {
public:
using value_type = T;
using iterator = Vector_iter;
//
...

Type aliases play a major role in generic programming by allowing the designer of classes to
provide common names for types in different classes (and class templates) with common semantics
...
The value_type and iterator
names are borrowed from the standard library’s container design (§33
...
3)
...
2
...


23
...
4 static Members
A static data or function member that is not defined in-class must have a unique definition in a program
...
4
...
4
...
*/ }
static void f2();
};
template int X::m1 = 88;
template int X::m3 = 99;

// error : two initializers

template void X::::f2() { /*
...
4
...
9
...

A static member need only be defined if it is used (§iso
...
2, §iso
...
4
...
2
...
For example:
template
struct X {
static int a;
static int b;
};
int∗ p = &X::a;

If this is all the mention of X in a program, we will get a ‘‘not defined’’ error for X::a, but
not for X::b
...
4
...
As usual, such a type can be a class
or an enumeration
...
*/ };
struct C2;
};
template
enum class X::E3 { a, b };

// needed

template
enum class X::E4 : char { x, y };

// needed

template
struct X::C2 { /*
...
4)
...


23
...
6 Member Templates
A class or a class template can have members that are themselves templates
...
For example, complex numbers are best represented as pairs of values of some scalar type:
template
class complex {
Scalar re, im;
public:
complex() :re{}, im{} {}
template
complex(T rr, T ii =0) :re{rr}, im{ii} { }

// default constructor

complex(const complex&) = default;
// copy constructor
template
complex(const complex& c) : re{c
...
imag()} { }
//
...
5
...
6):
complex<float> cf;
complex cd {cf};
complex<float> cf2 {cd};

// default value
// OK: uses float to double conversion
// error : no implicit double->float conversion

complex<float> cf3 {2
...
0};
// error : no implicit double->float conversion
complex cd2 {2
...
0F}; // OK: uses float to double conversion
class Quad {
// no conversion to int
};
complex cq;
complex ci {cq};

// error : no Quad to int conversion

Given this definition of complex, we can construct a complex from a complex or from a
pair of T2 values if and only if we can construct a T1 from a T2
...

Be warned that the narrowing error in the complex to complex<float> case will not be
caught until the instantiation of complex<float>’s template constructors and then only because I used
the {} initialization syntax (§6
...
5) in the constructor’s member initializers
...


Section 23
...
6

Member Templates

679

Using the (old) () syntax would leave us open to narrowing errors
...
real()), im(c
...

};
complex<float> cf4 {2
...
9}; // ouch! narrows
complex<float> cf5 {cd};
// ouch! narrows

I consider this yet another reason to be consistent in the use of the {} notation for initialization
...
4
...
1 Templates and Constructors
To minimize the chances of confusion, I explicitly added a default copy constructor
...

For technical reasons, a template constructor is never used to generate a copy constructor, so without the explicitly declared copy constructor, a default copy constructor would have been generated
...
5
...
6, §19
...
1)
must be defined as non-template operators or the default versions will be generated
...
4
...
2 Templates and virtual
A member template cannot be virtual
...

template
virtual bool intersect(const T&) const =0;
};

// error : vir tual template

This must be illegal
...
2
...
The linker would have to add a new entry to
the virtual table for class Shape each time someone called intersect() with a new argument type
...
In particular, handling dynamic linking would require implementation techniques rather different from what
is most commonly used
...
4
...
3 Use of Nesting
In general, it is a good idea to keep information as local as possible
...
This line of thinking leads to types
being defined as members
...
However, for members of class templates we must consider if the parameterization is appropriate for a member type
...
That can have unfortunate side
effects in cases where the behavior of the member does not in fact use every template argument
...
Consider:
template
class List {
private:
struct Link {
T val;
Link∗ succ;
Link∗ prev;
};
//
...
Thus, it seems a perfect example of a type best
defined in the scope of List and even kept private
...
But surprisingly, it can imply performance cost compared to using a nonlocal Link
type
...
Now List::Link and
List::Link are different types, so code using them cannot (without clever optimizers) be identical
...
This leads us to consider a design where Link isn’t a member:
template
class List;
template
class Link {
template
friend class List;
T val;
Link∗ succ;
Link∗ prev;
};
template
class List {
//
...
Except for making the name Link nonlocal, this preserves the design intent that Link is an implementation detail of List
...
4
...
3

Use of Nesting

681

But what if a nested class is not considered an implementation detail? That is, what if we need
an associated type that is meant for a variety of users? Consider:
template
class List {
public:
class Iterator {
Link∗ current_position;
public:
//
...

};
Iterator begin();
Iterator end();
//
...

However, because Iterator is a member and therefore formally depends on A (the compiler doesn’t
know anything to the contrary), we can’t write a function to process Lists independently of how
they were constructed using allocators:
void fct(List::Iterator b, List::Iterator e) // error : List takes two arguments
{
auto p = find(b,e,17);
//
...
begin(),lm
...
begin(),ly
...

}

However, that breaks our user():
void user(List& lm, List& ly)
{
fct(lm
...
end());
fct(ly
...
end());
// error : fct takes List::Iterators
}

682

Templates

Chapter 23

We could make fct a template and generate separate specializations for each allocator
...
Again, we solve the problem by moving Link out of the class template:
template
struct Iterator {
Link∗ current_position;
};
template
class List {
public:
Iterator begin();
Iterator end();
//
...
In this case, that was exactly what we wanted
...
Had fct() been defined to be a function template, there would have been only one copy
(instantiation) of the definition of fct()
...
’’ This is a special case of the general rule
to avoid unnecessary dependencies in code
...
4
...
4
...
3, a template class can designate functions as friends
...
4
...

};
template
class Matrix {
Vector v[4];
public:
friend Vector operator∗<>(const Matrix&, const Vector&);
//
...
Without the <>, a non-template function would be assumed
...
4
...
use m
...
v[i] for direct access to elements
...
Instead, friend functions and operators are found using a lookup
based on their argument types (§14
...
4, §18
...
5, §iso
...
3)
...
2
...

Like other classes, a class template can designate other classes as friends
...
For
example:
template
class my_other_class {
friend T;
friend My_class;
friend class T;
};

// my argument is my friend!
// My_class with the corresponding argument is my friend
// error : redundant ‘‘class’’

As ever, friendship is neither inherited nor transitive (§19
...
For example, C has not become a
friend of My_other_class even though My_class is a friend and C is a friend of
My_class
...
For example:
template
class List;
template
class Link {
template
friend class List;
//
...

Friend classes are designed to allow the representation of small clusters of closely related concepts
...


23
...
4), list (§31
...
2), and map (§31
...
3)
...
Sorting a vector is a simple example:
template void sort(vector&);

// declaration

void f(vector& vi, vector& vs)
{
sort(vi); // sor t(vector&);
sort(vs); // sor t(vector&);
}

When a function template is called, the types of the function arguments determine which version of
the template is used; that is, the template arguments are deduced from the function arguments
(§23
...
2)
...
7):
template
void sort(vector& v)
// Shell sort (Knuth, Vol
...
84)
{
const size_t n = v
...
5
...
Typically, it
is also faster because it doesn’t rely on a pointer to function for the comparison
...

A further simplification is to use the standard-library template swap() (§35
...
2) to reduce the
action to its natural form:
if (v[j+gap]swap(v[j],v[j+gap]);

Section 23
...
Better yet, the standard-library swap() uses move
semantics, so we may see a speedup (§35
...
2)
...
However, not every type has a < operator
...
2
...
For example:
template>
void sort(vector& v)
// definition
// Shell sort (Knuth, Vol
...
84)
{
Compare cmp;
// make a default Compare object
const size_t n = v
...

The explicit specification of function template arguments is explained in §23
...
2
...
5
...
4
...
2)
...

A compiler can deduce type and non-type arguments from a call, provided the function argument list uniquely identifies the set of template arguments
...

};
template
T& lookup(Buffer& b, const char∗ p);
Record& f(Buffer& buf, const char∗ p)
{
return lookup(buf,p); // use the lookup() where T is string and i is 128
}

Here, lookup()’s T is deduced to be string and max is deduced to be 128
...
The reason is that the flexibility provided by several constructors for a class would make such deduction impossible in many cases and
obscure in many more
...
3) provides a mechanism for implicitly choosing between alternative definitions of a template
...
For example, consider a simple variant of the standard library’s make_pair() (§34
...
4
...
7);

// x is a pair
// y is a pair

If a template argument cannot be deduced from the function arguments (§23
...
2), we must specify
it explicitly
...
2, §25
...
For example:
template
T∗ create();

// make a T and return a pointer to it

void f()
{
vector v;
int∗ p = create();
int∗ q = create();
}

// class, template argument int
// function, template argument int
// error : can’t deduce template argument

This use of explicit specification to provide a return type for a function template is very common
...
g
...
g
...
2
...
The syntax for static_cast, dynamic_cast, etc
...
5
...
2
...
5
...

Default template arguments can be used to simplify explicit qualification in some cases
(§25
...
5
...


23
...
2 Function Template Argument Deduction
A compiler can deduce a type template argument, T or TT, and a non-type template argument, I,
from a template function argument with a type composed of the following constructs
(§iso
...
8
...
1):
T
T∗
type[I]
TT
T type::∗
T (∗)(args)
type (type::∗)(args_TI)
T (type::∗)(args_TI)

const T
T&
class_template_name
T
T T::∗
type (T::∗)(args)
T (T::∗)(args_TI)
type (∗)(args_TI)

volatile T
T[constant_expression]
class_template_name
T<>
type T::∗
T (type::∗)(args)
type (T::∗)(args_TI)

Here, args_TI is a parameter list from which a T or an I can be determined by recursive application
of these rules, and args is a parameter list that does not allow deduction
...
For example:
template
void f(const T∗, U(∗)(U));
int g(int);
void h(const char∗ p)
{
f(p,g);
// T is char, U is int
f(p,h);
// error: can’t deduce U
}

Looking at the arguments of the first call of f(), we easily deduce the template arguments
...

If a template parameter can be deduced from more than one function argument, the same type
must be the result of each deduction
...
For example:
template
void f(T i, T∗ p);
void g(int i)
{
f(i,&i);
f(i,"Remember!");
}

// OK
// error, ambiguous: T is int or T is const char?

688

Templates

Chapter 23

23
...
2
...
Consider a class for holding
an {integer,pointer} pair:
template
class Xref {
public:
Xref(int i, T∗ p)
// store a pointer: Xref is the owner
:index{i}, elem{p}, owner{true}
{}
Xref(int i, T& r)
// store a pointer to r, owned by someone else
:index{i}, elem{&r}, owner{false}
{}
Xref(int i, T&& r)
// move r into Xref, Xref is the owner
:index{i}, elem{new T{move(r)}}, owner{true}
{}
˜Xref()
{
if(owned) delete elem;
}
//
...
Similarly, r2 picks Xref(int,string&) because x
is an lvalue
...
This differs from the binding of values to non-template argument rvalue references (§12
...
1) but is especially useful for argument forwarding (§35
...
1)
...
5
...
5
...
1

Reference Deduction

689

template
unique_ptr make_unique(int i, A&& a) // simple variant of make_shared (§34
...
2)
{
return unique_ptr{new TT{i,forward(a)}};
}

We want make_unique(arg) to construct a T from an arg without making any spurious copies
...
Consider:
auto p1 = make_unique>(7,"Here");

is an rvalue, so forward(string&&) is called, passing along an rvalue, so that Xref(int,string&&)
is called to move from the string holding "Here"
...
7
...
Thus,
Xref(int,string&) is called for the lvalue x, so that x is copied
...
Defining a make_unique() that can take arbitrary arguments is relatively easy using a variadic template for forwarding (§28
...
3)
...
5
...
When an overloaded function is
called, overload resolution is necessary to find the right function or function template to invoke
...
0); // sqr t(double)
sqrt(z); // sqr t(complex)
}

In the same way that a function template is a generalization of the notion of a function, the rules for
resolution in the presence of function templates are generalizations of the function overload resolution rules
...
Then, we apply the usual function overload resolution rules to these specializations and
all ordinary functions (§iso
...
8
...
2
...
Do this by considering each function template and deciding which template
arguments, if any, would be used if no other function templates or functions of the same
name were in scope
...
See also §23
...
3
...

[2] If two function templates can be called and one is more specialized than the other
(§25
...
3), consider only the most specialized template function in the following steps
...

[3] Do overload resolution for this set of functions, plus any ordinary functions, as for ordinary functions (§12
...
If a function template’s argument has been determined by template argument deduction (§23
...
2), that argument cannot also have promotions, standard
conversions, or user-defined conversions applied
...

[4] If a function and a specialization are equally good matches, the function is preferred
...
0)
...
If we end up with two or more equally good
matches, the call is ambiguous and is an error
...
7,4
...
7,4);

// max(1,2)
// max(’a’,’b’)
// max(2
...
9)
// max(int{s},7) (trivial conversion used)
// error: ambiguous: max() or max()?
// error: ambiguous: max() or max()?

}

The problem with the last two calls is that we don’t apply promotions and standard conversions
until after template parameters have been uniquely determined
...
In most cases, it is probably good that the language
rules leave subtle decisions in the hands of the programmer
...
People’s ‘‘intuitions’’ about overload
resolution differ dramatically, so it is impossible to design a perfectly intuitive set of overload resolution rules
...
5
...
1

Ambiguity Resolution

691

23
...
3
...
7,4);
}

// max(int(’a’),1)
// max(2
...
7,4);
}

// max(int(’a’),1)
// max(2
...
3) apply, and the use of inline ensures that
no extra overhead is imposed
...
However, using an explicit specialization of the template is
an easy way of defining such resolution functions and can help maintenance by avoiding almost
identical code in several functions
...
5
...
2 Argument Substitution Failure
When looking for a best match for a set of arguments for a function template, the compiler considers whether the argument can be used in the way required by the complete function template declaration (including the return type)
...
begin(),v
...
The initialization of y fails because even though the arguments match,
int∗ does not have a member called value_type, so we cannot say:
int∗::value_type mean(int∗,int∗);

// int* does not have a member called value_type

However, what if there were another definition of mean()?

692

Templates

Chapter 23

template
typename Iter::value_type mean(Iter first, Iter last);

// #1

template
T mean(T∗,T∗);

// #2

void f(vector& v, int∗ p, int n)
{
auto x = mean(v
...
end());
auto y = mean(p,p+n);
}

// OK: call #1
// OK: call #2

This works: both initializations succeed
...
Fortunately, considering
this possible declaration is not by itself an error
...
14
...
2) that says
that such a substitution failure is not an error
...
That done, mean(p,p+n)
matches declaration #2, which is called
...
More, this rule gives us a general tool for
selecting among templates
...
4
...
4
...

The rule is known under the unpronounceable acronym SFINAE (Substitution Failure Is Not An
Error)
...
’’ That sounds quite impressive, but I tend to avoid this jargon
...

So, if – in the process of generating a candidate function to resolve a function call – the compiler finds itself generating a template specialization that would be nonsensical, that candidate is
not entered into the overloading set
...
In this, we consider only a declaration; template function definitions and the
definition of class members are not considered (or generated) unless they are actually used
...

}
template
T∗ mean(T∗,T∗);

// #1

// #2

Section 23
...
3
...
begin(),v
...
The compiler does not start to instantiate the
body of that mean() and eliminate it because of the type error
...
Had mean() #2 not been present, declaration #1 would
have been chosen and we would have suffered an instantiation-time error
...


23
...
3
...
*/ };
template
class D : public B { /*
...
We have an argument of
type D∗, so the compiler easily deduces that by choosing T to be int, the call can be uniquely
resolved to a call of f(B∗)
...
5
...
4 Overloading and Non-Deduced Parameters
A function argument that is not involved in the deduction of a template parameter is treated exactly
as an argument of a non-template function
...
Consider:
template
T get_nth(C& p, int n); // get the nth element

This function presumably returns the value of the nth element of a container of type C
...
However, the second argument is perfectly ordinary, so the full range of possible conversions is considered
...

};
void f(vector& v, short s, Index i)
{
int i1 = get_nth(v,2); // exact match
int i2 = get_nth(v,s); // standard conversion: short to int
int i3 = get_nth(v,i); // user-defined conversion: Index to int
}

This notation is sometimes called explicit specialization (§23
...
1)
...
6 Template Aliases
We can define an alias for a type with the using syntax or with the typedef syntax (§6
...
The using
syntax is more general in the important sense that it can be used to define an alias for a template
with some of its arguments bound
...
Note that what we get from using in an alias definition is always an alias
...
For example:
vector> vc2 = vc;
vector> verbose = fib;

// vc2 and vc are of the same type
// verbose and fib are of the same type

The equivalence of the alias and the original template implies that if you specialize the template,
you (correctly) get the specializations when you use the alias
...
6

Template Aliases

695

template<>
struct int_exact_traits<16> {
using type = short;
};
template
using int_exact = typename int_exact_traits::type; // define alias for convenient notation
int_exact<8> a = 7; // int_exact<8> is an int with 8 bits

If specializations did not get used through the alias, we couldn’t claim that int_exact was simply an
alias for int_exact_traits::type; they would behave differently
...
If you had been able to, it would have been rather easy for a
human reader to get confused about what was specialized, so no syntax is provided for specializing
an alias
...
7 Source Code Organization
There are three reasonably obvious ways of organizing code using templates:
[1] Include template definitions before their use in a translation unit
...
Include definitions of templates later in the translation unit (potentially after their use)
...
Define the templates in some other translation unit
...
By far the most common approach is to include (usually #include) the
definition of the templates you use in every translation unit in which you use them and rely on your
implementation to optimize compile times and eliminate object code duplication
...
h:
// file out
...
For example:
// file user1
...
h"
// use out()

696

Templates

Chapter 23

and
// file user2
...
h"
// use out()

That is, the definition of out() and all declarations on which it depends are #included in several different compilation units
...
This strategy treats template functions the same
way as inline functions
...
This danger can be limited by taking
approach [2] ‘‘include template definitions later,’’ by using namespaces, by avoiding macros, and
generally by reducing the amount of information included
...

To use the ‘‘include template definitions later’’ approach for our simple out() example, we first
split out
...
The declarations go into a
...
h:
template
void out(const T& t);

The definitions go into out
...
cpp:
#include
template
void out(const T& t)
{
std::cerr << t;
}

A user now #includes both:
// file user3
...
h"
// use out()
#include "out
...
Unfortunately, it also increases the chances that something in the user code (say, a
macro) will have an undesirable effect on the template definitions
...
2
...
This implies that such members are best not used for templates that are otherwise included in many translation units
...
7

Source Code Organization

697

subtly change the meaning of a definition:
// file user1
...
h"
// use out()

and
// file user4
...
c"
// use out()

This sneaky and error-prone use of a macro changes the definition of out so that user4
...
cpp’s
...
This kind of error can be very hard to detect in large programs, so be careful to minimize
context dependencies of templates and be very suspicious about macros (§12
...

If you need more control over the context of instantiation, you can use explicit instantiation and
extern templates (§26
...
2)
...
7
...
2, §15
...
3)
...

For templates defined in header files and included ‘‘everywhere’’ this can imply a lot of recompilation because templates tend to include a lot of information in header files, more than non-template code using
...
In particular, if dynamically linked libraries are used, care has to be
taken that all uses of a template are consistently defined
...
For example, I might like to
implement some computations using a general numerical library supporting a wide variety of types
(e
...
, Chapter 29, §40
...
5, §40
...
However, I often know the type used for my calculations
...
In that case, I could
define:
double accum(const vector& v)
{
return accumulate(v
...
end(),0
...
cpp file that is not seen by the rest of my
code
...
cpp file
...

I suspect that I would not use this technique for standard-library templates
...
In particular, I did not bother to try to encapsulate
vector
...

late()
...
8 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]
[14]
[15]
[16]
[17]

Use templates to express algorithms that apply to many argument types; §23
...

Use templates to express containers; §23
...

Note that template and template are synonymous; §23
...

When defining a template, first design and debug a non-template version; later generalize by
adding parameters; §23
...
1
...
3
...
3
...
4
...
1
...
4
...
1
...
4
...
2
...
4
...
3
...
5
...

Overload function templates to get the same semantics for a variety of argument types;
§23
...
3
...
5
...
2
...
6
...
7
...
7
...

Separately compile large templates and templates with nontrivial context dependencies;
§23
...


24
Generic Programming
Now is a good time to put your work
on a firm theoretical basis
...
1 Introduction
What are templates for? In other words, what programming techniques are effective when you use
templates? Templates offer:
• The ability to pass types (as well as values and templates) as arguments without loss of
information
...

• Delayed type checking (done at instantiation time)
...

• The ability to pass constant values as arguments
...

In other words, templates provide a powerful mechanism for compile-time computation and type
manipulation that can lead to very compact and efficient code
...


700

Generic Programming

Chapter 24

The first and most common use of templates is to support generic programming, that is, programming focused on the design, implementation, and use of general algorithms
...
The template is C++’s main support for generic programming
...

There are many definitions of ‘‘generic programming
...
However, in the context of C++, ‘‘generic programming’’ implies an emphasis on the design of general
algorithms implemented using templates
...

The type checking provided for templates checks the use of arguments in the template definition
rather than against an explicit interface (in a template declaration)
...
Or – using more technical terminology – we operate on values, and the presence and
meaning of an operation depend solely on its operand values
...
Values ‘‘live’’ in
objects
...
g
...
What is done at compile time using templates does not involve
objects, only values
...
Thus, template programming resembles programming in dynamically-typed programming languages, but the run-time cost
is zero, and errors that in a run-time typed language manifest themselves as exceptions become
compile-time errors in C++
...
For example, an accumulate() operation does not care whether the types of values it adds up are ints, complexs, or Matrixes
...
The use of a type as a template
argument does not imply or require the use of a class hierarchy or any form of run-time self-identification of the type of an object
...

This section focuses on two aspects of generic programming:
• Lifting: generalizing an algorithm to allow the greatest (reasonable) range of argument types
(§24
...
3)

24
...
An algorithm is a procedure or formula for solving a problem: a finite series of computation steps to produce a result
...


Section 24
...
Such generalization is
called lifting: that is, lifting a general algorithm from specific functions
...
Overly clever programmers can generalize to an absurd extent to try to cover every eventuality
...

I will illustrate the process of lifting by a concrete example
...
Also consider:
struct Node {
Node∗ next;
int data;
};
int sum_elements(Node∗ first, Node∗ last)
// another concrete algorithm on list of ints
{
int s = 0;
while (first!=last) {
s += first−>data;
first = first−>next;
}
return s;
}

This computes the sum of the ints in the singly-linked list implemented by the Nodes
...
’’ This is a
popular algorithm
...
However, let us try to develop a general algorithm from the two concrete examples
in stages, so as to get a feel for the process of lifting
...
int, or
• array vs
...


702

Generic Programming

Chapter 24

To do so, I write some pseudo code:
// pseudo code:
T sum(data)
// somehow parameterize by the value type and the container type
{
Ts=0
while (not at end) {
s = s + current value
get next data element
}
return s
}

To make this concrete, we need three operations to access the ‘‘container’’ data structure:
• Not at end
• Get current value
• Get next data element
For the actual data, we also need three operations:
• Initialize to zero
• Add
• Return the result
Obviously, this is rather imprecise, but we can turn it into code:
// concrete STL-like code:
template
Val sum(Iter first, Iter last)
{
Val s = 0;
while (first!=last) {
s = s + ∗first;
++first;
}
return s;
}

Here, I took advantage of knowing the usual STL way of representing a sequence of values (§4
...

The sequence is represented as a pair of iterators supporting three operations:
• ∗ for accessing the current value
• ++ for moving forward to the next element
• != for comparing iterators to check if we are at the end of a sequence
We now have an algorithm (a function template) that can be used for both arrays and linked lists
and for both ints and doubles
...
2

Algorithms and Lifting

703

To use the handcrafted singly-linked list, we need to provide an iterator for it
...
I use an explicit template argument (here, ) to allow a caller
to specify the type to use for the accumulator variable
...
For example, sum() would
work for lists of floating-point numbers (of all precisions), for arrays of integers (of all ranges), and
for many other types, such as a vector
...
We do not want to achieve generality at the cost of performance
...
In particular, the
use of an extra template argument is awkward, and we required the initial value 0
...
0);
double s2 = accumulate(ad,ad+4,0);

// accumulate in a double
// accumulate in an int

But why +? We sometimes want to multiply elements
...
This leads to a further generalization:
template
Val accumulate(Iter first, Iter last, Val s, Oper op)
{
while (first!=last) {
s = op(s,∗first);
++first;
}
return s;
}

704

Generic Programming

Chapter 24

We now use the argument op to combine element values with the accumulator
...
0,std::plus);
// as before
double s2 = accumulate(ad,ad+4,1
...
Here, we see the utility of having the caller supply the initial value: 0 and ∗
don’t go well together for accumulation
...
6)
...
The
most important single guide for designing algorithms is to lift them from concrete examples without adding features (notation or run-time cost) that would impair their use
...


24
...
5
...
3)
• Types for which == compares equality and others for which compare() does that
• Types that define addition as a member function plus() and others that define it as a nonmember function operator+()
In that direction lies chaos
...
Conversely, if each template’s requirements are unique, it
becomes difficult to define types that can be used with many templates
...
What we need to do is to identify a small number of concepts (sets of requirements) that can be used for many templates and many types as arguments
...


24
...
1 Discovering a Concept
As an example, consider the String class template from §23
...

};

What is required of a type, X, for it to be used as an argument to String: String? More generally,

Section 24
...
1

Discovering a Concept

705

what does it take to be a character in such a character string class? An experienced designer will
have a small number of likely answers to that question and start the design based on those
...
We proceed through three stages
of analysis:
[1] First, we look at our (initial) implementation and determine which properties (operations,
functions, member types, etc
...
The resulting list is the minimal requirements for that particular template
implementation
...
Doing so, we may decide that we should place more
or stricter requirements on the template arguments to allow for alternative implementations
...

[3] Finally, we look at the resulting list (or lists) of required properties and compare it to lists
of requirements (concepts) that we have used for other templates
...
The aim here is to make our design benefit from general work on classification
...
They should also maximize the degree of interoperability of templates and
types by limiting variations in concepts to what is essential
...
2)
...

Such requirement lists are overspecialized and not stable: each change to the implementation would
imply changes to the requirements documented as part of the algorithm’s interface
...
3)
...

[2] String compares Cs using == and !=
...

[4] String takes the address of Cs
...

[6] String has >> and << operators that somehow must read and write Cs
...
The
first requirement – that values can be copied – is not true for a few important types, such as
std::unique_ptr, that represent real resources (§5
...
1, §34
...
1)
...
The ability to invoke a copy operation goes together with the
semantic requirement that a copy really is a copy of the original, that is, that – except for taking the
address – the two copies behave identically
...

By requiring assignment, we imply that a const type cannot be used as a template argument
...
That’s fine in this case, as in most

706

Generic Programming

Chapter 24

cases
...
It does not imply that we cannot use
const to specify interfaces
...
size()!=s2
...
size(); ++i)
if (s1[i]!=s2[i]) return false;
return true;
}

For String we require that objects of type X can be copied
...

Should we require a move for an element type C? After all, we provide move operations for
String
...
g
...
In particular, potentially important examples, such as String>, will work fine (correctly and
efficiently) without adding move operations to the requirements
...
Do we really read and write every kind of string? Maybe it would be better to say that if
we read and write a String, then X must provide >> and < ...
The latter is more flexible, but also more verbose (we have to express
the requirement for each function that needs it) and harder for a programmer to remember
...
g
...
3
...
The central concept for ‘‘ordinary types’’ is regular
...
5
...
3),
• you can default construct,
• doesn’t have problems with various minor technical requirements (such as taking the
address of a variable),
• you can compare for equality (using == and !=)
...
I considered leaving out the
equality comparisons but decided that copying without equality is rarely useful
...
All the built-in types are regular
...
3
...
The
desired use of a template (such as String) should determine its requirements on its arguments
...
Also, the standard-library string does provide <
...
So, we require not just Regular for
our String, but also ordering
...

Interestingly, there has been quite some debate on whether Regular should require < or not
...
For example, characters are encoded
in bit patterns that can be interpreted as integers, and any sequence of values can be lexicographically ordered
...
g
...
Other types have several natural orderings, but no
unique best ordering (e
...
, records may be ordered by name or by address)
...
For example, consider:
enum class rsp { rock, scissors, paper };

The rock-scissors-and-paper game critically depends on
• scissors• rock• paper ...

Adding a default constructor and the == and < operator, to our requirements for String’s template
argument allows us to provide several useful operations for String
...
On the other hand, it is important not to load
down a template with requirements that are only used rarely and by specific operations: each
requirement places a burden on the implementer of argument types and limits the set of types that
can be used as arguments
...
In addition, we must require that these
operations have the right semantics; for example, a copy operation makes a copy, == (equality)
compares for equality, and < (less than) provides ordering
...
For example, for the standard library, we have (§31
...
2
...
5
...
3)
...
g
...
2
...
1)
...
4
...
For the standard
library, you can find the semantic requirements written in formalized English in the ISO standard
...
3
...
Most lists of properties of a type (or a set of
types) do not define a coherent and useful concept
...
In many
fields of endeavor, people have designed or discovered concepts describing the fundamental concepts of the field (the technical use of the word ‘‘concept’’ in C++ was chosen with this common
usage in mind)
...
For example, algebra
builds on concepts such as monad, field, and ring, whereas the STL relies on concepts such as forward iterator, bidirectional iterator, and random-access iterator
...
Mostly, you find
concepts by examining the foundational texts of a field of study or an application domain
...
4
...

‘‘Concepts’’ is a very general idea that does not inherently have anything to do with templates
...
Our requirements on template arguments are
concepts (however expressed), so most interesting issues related to concepts come in the context of
templates
...
Consequently, there should be only few concepts, and these can act as a guideline for the
design of algorithms and types
...
This ideal can
conflict with the ideal of minimal requirements for each individual generic algorithm (§24
...
Furthermore, the ideal can conflict with the ideal of providing
absolutely minimal interfaces to classes (§16
...
3) and even with what some programmers regard as
their right to write their code ‘‘exactly as they like
...

I set the bar for being a concept very high: I require generality, some stability, usability across
many algorithms, semantic consistency, and more
...
I think that is unavoidable
...
Instead, they are implementation details, and their arguments only have to reflect the
necessary details of a template intended for a single use in a single implementation of something
...
One
way to look at constraints is to consider them incomplete (partial) specifications of an interface
...

As an example, consider a library for experimenting with balancing strategies for balanced
binary trees
...

}

A balancer is simply a class that provides three operations on nodes
...
3
...

template static void add_fixup(Node∗ x);
template static void touch(Node∗ x);
template static void detach(Node∗ x);
};

Obviously, we’d like to say what’s required of node_base’s arguments, but a balancer is not meant
to be a widely used and easily understood interface; it’s meant to be used only as a detail of a particular implementation of balanced trees
...
It would be hard to pin down the exact semantics of a balancer
...
In those
aspects, a Balancer differs from a proper concept, such as Random_access_iterator
...

Note the way ‘‘semantics’’ keep cropping up in the discussion of concepts
...
If I can write out a meaningful semantic specification, I have a concept
...


24
...

However, handling ‘‘concepts’’ as a design notion only and presenting them informally as comments is not ideal
...
Experience shows that even though concepts cannot be represented perfectly without direct language support, we can approximate them using code that performs compile-time
checks of template argument properties
...
So, we implement a concept as a constexpr function
...

In contrast to proper concepts, a constraints check does not deal with semantic issues; it simply
checks assumptions about syntactic properties
...

};

When

String

is instantiated for a type X, the

static_assert

will be executed by the compiler
...
Otherwise, the error message is produced
...
I’d rather have said:
template
class String {
//
...


Let us ‘‘dig down’’ to see what

template
constexpr bool Totally_ordered()
{
return Equality_comparable() // has == and !=
&& Has_less()&& Boolean>()
&& Has_greater() && Boolean>()
&& Has_less_equal() && Boolean>()
&& Has_greater_equal() && Boolean>();
}
template
constexpr bool Equality_comparable()
{
return Has_equal() && Boolean>()
&& Has_not_equal() && Boolean>();
}

So, a type T is ordered if it is regular and provides the usual six comparison operations
...
The comparison operators
are also supposed to have their proper mathematical meaning
...
2
...
1, §iso
...
4)
...
4
...

I capitalize my constraints names (e
...
, Regular) even though doing so violates my ‘‘house
style’’ of capitalizing type and template names, but not functions
...
I also keep them in a separate
namespace (Estd) in the hope that very similar names will eventually become part of the language
or the standard library
...
4

Making Concepts Concrete

711

template
constexpr bool Regular()
{
return Semiregular() && Equality_comparable();
}

gives us == and !=
...
That describes most types, but there are examples of
types that cannot be copied, such as unique_ptr
...
Types that can neither be moved nor copied, such as type_info (§22
...

We can also use constraints checks for functions; for example:
template
ostream& operator<<(ostream& out, String& s)
{
static_assert(Streamable(),"String's character not streamable");
out << '"';
for (int i=0; i!=s
...
3, Chapter 38) for a type
...
That is,
a concept is part of the interface to an abstraction, but a constraints check can be used only
in its implementation
...
Therefore, the checking may occur later than we would like
...

• We can forget to insert a constraints check (especially for a function template)
...
Thus, a template implementation may pass the constraints check, yet
still fail to type check
...
g
...

Adding constraints checks makes the requirements on template arguments explicit, and if a constraints check is well designed, it leads to more comprehensible error messages
...
That can be unfortunate, but it is not disastrous
...

If we want to, we can place constraints checks almost anywhere
...
g
...
For example:
static_assert(Ordered,"std::string is not Ordered");
// will succeed
static_assert(Ordered>,"String is not Ordered"); // will fail

The first static_assert checks if the standard string is Ordered (it is, because it provides ==, !=, and
<)
...
Using
such a global check will perform the constraints check independently of whether we actually use
that particular specialization of a template in the program
...
Such a check forces type checking to be done at a specific point in the program; that is usually good for error isolation
...
However, for
programs using a number of libraries, explicit checks quickly become unmanageable
...
We can copy objects of regular types, put them into vectors
and arrays, compare them, etc
...
So, we go back and improve our String to make it Ordered
...
size() && i!=s2
...
size() ...
size()==s2
...
4

Making Concepts Concrete

713

24
...
1 Axioms
As in mathematics, an axiom is something we can’t prove
...

In the context of requirements for template arguments, we use ‘‘axiom’’ in that sense to refer to
semantic properties
...
An axiom, however expressed, represents an algorithm’s or class’s expectations of (assumptions about) its arguments
...
Furthermore, an axiom is only required to
hold for the values actually used by an algorithm
...
If so, it could have axioms that
require pointers to be dereferenceable and floating-point values to be copyable
...
g
...

C++ does not (currently) have any way of expressing axioms, but as for concepts, we can make
our idea of a concept a bit more concrete than a comment or some text in a design document
...

template
bool Move_effect(T x, T& y)
// semantics of move
{
return (x==y ? T{std::move(x)}==y) : true) && can_destroy(y);
}
template
bool Move_assign_effect(T x, T& y, T& z)
// semantics of move assignment
{
return (y==z ? (x=std::move(y), x==z)) : true) && can_destroy(y);
}

In other words, a move operation yields a value that compares equal to whatever the source of the
move operation compared equal to, and the source of the move can be destroyed
...
We might use them for testing, but most
importantly, we have to think harder to express them than we would have to simply write a comment
...
’’ Basically, we can express such pseudo axioms using first-order predicate logic
...
4
...
That’s part of the
story, but only a part
...
Consider the standard-library find() algorithm:
template
Iter find(Iter b, Iter e, Val x);

The Iter template argument must be an input iterator, and we can (relatively) easily define a constraints-check template for that concept
...

We need to specify that comparison is required; that is, we need to state that Val and and the value
type of the input iterator are equality comparable
...
However, I wanted to be explicit about all of the operators and about the symmetry of their use rather than burying the complexity in a generalization
...
4
...

This is also the area where you find the greatest number of concepts and the greatest need to specify new concepts (as opposed to picking ‘‘standard ones’’ from a catalog of common concepts)
...


24
...
3 Value Concepts
Concepts can express arbitrary (syntactic) requirements on a set of template arguments
...
For
example, we can write a constraints check to test that a value template argument is small:
template
constexpr bool Small_size()
{
return N<=8;
}

A more realistic example would be a concept for which the numeric argument was just one among
others
...
’’ It might be used like this:
template
struct Buffer {
//
...

}

Compared to the fundamental concepts for types, value concepts tend to be small and ad hoc
...
4
...
They are not part
of a standard, and I hope that in the future they will be replaced by a proper language mechanism
...
They should go in a separate namespace to avoid interfering with
possible future language features and alternative implementations of the idea of concepts
...
4
...
Here are a few constraints checks that you
might find useful:
• Input_iterator: X is an iterator that we can use only once to traverse a sequence (forward
using ++), reading each element once only
...

• Forward_iterator: X is an iterator that we can use to traverse a sequence (forward using
++)
...
g
...

• Bidirectional_iterator: X is an iterator that we can move both forward (using ++) and backward (using −−)
...
g
...

• Random_access_iterator: X is an iterator that we can use to traverse a sequence (forward
and backward) and to randomly access elements using subscripting and positioning using +=
and −=
...

• Equality_comparable: An X can be compared with a Y using == and !=
...

• Semiregular: Xs can be copied, default constructed, allocated on the free store, and are
free of minor annoying technical restrictions
...
The standard-library
containers require their elements to be regular
...
The standard-library associative containers
require their elements to be ordered unless you explicitly provide a comparison operation
...

• Predicate: An F can be called for an X yielding a bool
...

• Movable: An X can be moved; that is, it has a move constructor and a move assignment
...

• Copyable: An X is Movable and can also be copied
...

• Common: An X and a Y can unambiguously be converted to a common type called
Common_type
...
1
...
For example, Common_type is Base∗ and Common_type is long
...
5
...
begin() and x
...

Obviously, these definitions are informal
...
4
...
g
...
17
...
3)
...
4
...
4
...
If
the implementation of a template in fact uses more properties than its concepts guarantee, we may
get type errors
...
However, the constraints check does not help us detect that problem
...
begin(),lst
...
begin(),vs
...

}

// error : list does not provide +
// OK: vector provides +

The call of find() for the list will fail (because + is not defined for the forward iterator provided by
list) and the call for the vector will succeed (because b+1 is fine for vector::iterator)
...
On the other hand, constraints checks
do not help a template writer who would like to be sure that the implementation doesn’t use any
properties beyond those specified in the concepts
...
So, how do we test the implementation of
a parameterized class or a generic algorithm?
Concepts provide a strong guideline: the implementation should use no property of an argument
that isn’t specified by the concepts, so we should test the implementation with arguments that provide the properties specified by the implementation’s concepts, and only those
...

So, for the find() example, we look at Forward_iterator and Equality_comparable or at the standard’s definition of the forward-iterator and equal-comparable concepts (§iso
...
6
...
1, §iso
...
2
...

Then, we decide that we need an Iterator type that provides at least:

718

Generic Programming

Chapter 24

• A default constructor
• A copy constructor and a copy assignment
• Operators == and !=
• A prefix operator ++
• A type Value_type
• A prefix operator ∗
• The ability to assign the result of ∗ to a Value_type
• The ability to assign a Value_type to the result of ∗
This is slightly simplified from the standard-library forward iterator, but sufficient for find()
...

Given this list, we need to find or define a type that provides only the desired features
...
This is
because ‘‘forward iterator’’ was defined to express the idea of something that allows us to iterate
through a singly-linked list
...
If we decide to use an existing type, we have to be careful, though, not to pick a type that
is more flexible than required
...
However, the very generality and flexibility that make vector so popular
make it unusable as an archetype for many simple algorithms
...
That is done
by going through the list of requirements and defining suitable members:
template
struct Forward {
// for checking find()
Forward();
Forward(const Forward&);
Forward operator=(const Forward&);
bool operator==(const Forward&);
bool operator!=(const Forward&);
void operator++();
Val& operator∗();
// simplified: does not handle a proxy for Val
};
template
using Value_type> = Val;

// simplified; see §28
...
4

void f()
{
Forward p = find(Forward{},Forward{},7);
}

At this level of testing, we need not check that these operations actually implement the right semantics
...

Here, I have simplified the testing by not introducing an archetype for the Val argument
...
Testing nontrivial conversions between an archetype for Val and an
archetype for Iter would be significantly more work and most likely not particularly useful
...


Section 24
...
5

Template Definition Checking

719

Using a relatively small and well-specified set of concepts makes the task manageable
...

Note that this simple specification and checking strategy leads to find() requiring its iterator
argument to have a Value_type type function (§28
...
That allows pointers to be used as iterators
...
2
...
2
...


24
...
1
...
1
...
1
...
2
...
3
...
3
...
3
...
3
...
3
...

A concept is not just a description of the needs of a particular implementation of an algorithm; §24
...
1
...
3
...
4
...

The default concept for a template argument is Regular; §24
...
1
...
3
...

A concept requires a semantic aspect; it is not primarily a syntactic notion; §24
...
1, §24
...
2,
§24
...
1
...
4
...
4
...
4
...

Use axioms as a guide for testing; §24
...
1
...
4
...

Concepts are not just types of types; §24
...
2
...
4
...

Use concepts as a guide for testing template definitions; §24
...
5
...

It’s what you know for sure that just ain’t so
...
1 Introduction
Over the last two decades, templates have developed from a relatively simple idea to the backbone
of most advanced C++ programming
...
g
...
5);
• raising the general level of abstraction of programs (e
...
, by using standard containers and
algorithms; §4
...
5, §7
...
3, Chapter 31, Chapter 32); and
• providing more flexible, type-safe, and efficient parameterization of types and algorithms
(§25
...
3)
...
Most techniques also rely on the type deduction mechanisms offered by templates (sometimes called compile-time polymorphism; §27
...
These techniques are the backbone of C++ use in performance-critical areas, such as high-performance
numerical computing and embedded systems programming
...


722

Specialization

Chapter 25

This chapter and the following two present simple examples of the advanced and/or specialized
language features supporting techniques aimed at uncompromised flexibility and performance
...
Like most
programmers, I prefer to forget about the more advanced techniques most of the time
...

Templates are introduced in §3
...
This chapter is part of a sequence presenting templates and
their uses:
• Chapter 23 gives a more detailed introduction to templates
...

• Chapter 25 (this chapter) shows how to specialize a template with a set of arguments
...

• Chapter 27 discusses the relation between templates and class hierarchies
...

• Chapter 29 presents a larger example of template-based programming techniques
...
2 Template Parameters and Arguments
A template can take parameters:
• Type parameters of ‘‘type type’’
• Value parameters of built-in types such as ints (§25
...
2) and pointers to functions (§25
...
3)
• Template parameters of ‘‘type template’’ (§25
...
4)
Type parameters are by far the most common, but value parameters are essential for many important techniques (§25
...
2, §28
...

A template can take a fixed number of parameters or a variable number
...
6
...
This is acceptable because such names tend to be
conventional and restricted to a relatively small scope (§6
...
3)
...
6), so don’t use names that are long enough
to clash with likely macro names
...
2
...
The
result of using either is completely equivalent
...
For example:
template
void f(T);
template
class X {
//
...
2
...
The validity of an argument type depends
exclusively on its use in the templates, providing a form of duck typing (§24
...
You can implement general constraints as concepts (§24
...

User-defined and built-in types are handled equivalently when used as template arguments
...
For example:
vector x1;
vector> x2;

// vector of doubles
// vector of complex

In particular, there is no space or time overhead implied by using either compared to the other:
• Values of built-in types are not ‘‘boxed’’ into special container objects
...
g
...
’’
• Values of user-defined types are not implicitly accessed through references
...
For example:
class X {
class M { /*
...

void mf();
};
void f()
{
struct S { /*
...

}
void M::mf()
{
vector vs;
vector vm;
//
...
2
...
For example, integer arguments come in handy for supplying sizes
and limits:
template
class Buffer {
T v[max];
public:
Buffer() { }
//
...
They avoid the use of free store implied by the use of a more general
string or vector while not suffering from the implicit conversions to a pointer like a built-in array
(§7
...
The standard-library array (§34
...
1) implements this idea
...
14
...
2):
• An integral constant expression (§10
...
2)
• A nonoverloaded pointer to member (§20
...
2
...
A pointer to member must be of the
form &X::of, where of is the name of a member
...

};
X x1;
char lx2[] = "BMW323Ci";
X x2;

// error : string literal as template argument
// OK: lx2 has external linkage

This restriction, like the one against floating-point template value arguments, exists to simplify
implementation of separately compiled translation units
...
Resist the temptation to try
something more clever
...
4
...
The value template arguments are the mechanism for some
more advanced compile-time computation techniques (Chapter 28)
...
For example:

Section 25
...
2

Values as Arguments

725

constexpr int max = 200;
void f(int i)
{
Buffer bx;
Buffer bm;
//
...
For example:
template
class Buffer {
T v[max];
public:
Buffer(int i) { max = i; } // error : attempt to assign to template value argument
//
...
For example:
template
class Vec {
//
...
2
...

};
Vec c1;
Vec c11;
Vec c2;
Vec c22;

// default_value is int{}, that is, 0
// default_value is string{}; that is, ""

25
...
3 Operations as Arguments
Consider a slightly simplified version of the standard-library map (§31
...
3):
template
class map {
//
...
For example, by default, the map uses < for
comparison, but not all Keys have a < that we would want to use
...
For example, one of the most
common Key types is string and strings can be ordered based on a variety of criteria (e
...
,
case sensitive and case insensitive)
...
In
principle, the notion of sorting criteria for a map could be represented as:
[1] A template value argument (e
...
, a pointer to a comparison function)
[2] A template type argument to the map template determining the type of a comparison
object
At first glance, the first solution (pass a comparison object of a specific type) seems simpler
...

};

This map requires a user to supply the comparison as a function:
bool insensitive(const string& x, const string& y)
{
// compare case insensitive (e
...
, "hello" equals "HellO")
}
map m;

// compare using insensitive()

However, this is not very flexible
...
Also, because the argument types of the comparison operator must depend on the Key type, it
can be hard to provide a default comparison criterion
...
For example:
template>
class map {
public:
map() { /*
...
*/ }
// override the default
//
...
If we want a different

Section 25
...
3

Operations as Arguments

727

comparison criterion, we can supply it as a function object (§3
...
3):
map m1;

// use the default comparison (less)

map> m2;

// compare using greater()

Function objects can carry state
...
2
...
4
...
For example:
using Cmp = bool(∗)(const string&,const string&);
map m4 {insensitive};
// compare using a pointer to function
map m4 {[](const string& a, const string b) { return a>b; } };

Passing the comparison operations as a function object has significant benefits compared to passing
pointers to functions:
• A simple class member function defined in-class is trivial to inline, whereas inlining a call
through a pointer to function requires exceptional attention from a compiler
...

• Several operations can be passed as a single object with no additional run-time cost
...
However, the technique used to pass it is
general and very widely used to parameterize classes and functions with ‘‘policies
...
5
...
4), allocators for containers (§31
...
4), and deleters
for unique_ptr (§34
...
1)
...
g
...
4)
...
We could name the lambda and then use that name:
auto cmp = [](const string& x, const string& y) const { return xmap c4 {cmp};

I find naming operations useful from a design and maintenance point of view
...


25
...
4 Templates as Arguments
Sometimes it is useful to pass templates – rather than classes or values – as template arguments
...

};
template
using My_vec = vector;
Xrefd x1;

// use default allocator

// store cross references for Entrys in a vector

template
class My_container {
//
...
For example, we specify that Xrefd’s template parameter C is a template class that takes a single type argument
...
The point of using a template
as a template parameter is usually that we want to instantiate it with a variety of argument types
(such as T and T∗ in the previous example)
...

Only class templates can be template arguments
...
5
...
For example:
template
class Xrefd2 {
C mems;
C2 refs;
//
...
2) for obtaining
the type of elements of a container, for example, Value_type
...
5
...


25
...
5 Default Template Arguments
Explicitly specifying the comparison criterion for each use of map is tedious – especially as
less is typically the best choice
...
2
...

};
map m1;
map> m2;

// will use less for comparisons
// same type as m1

struct No_case {
// define operator()() to do case-insensitive string comparison
};
map m3;

// m3 is of a different type from m1 and m2

Note how the default map constructor creates a default comparison object, Compare{}
...
If we want a more elaborate construction, we must do so explicitly
...
In particular, as long as we refrain from using the default template argument less, we can compare() values of a type X for which less wouldn’t compile
...
g
...
4)
...
2
...

};
template
class X2 {
// OK
//
...


730

Specialization

Chapter 25

The technique of supplying a policy through a template argument and then defaulting that argument to supply the most common policy is almost universal in the standard library (e
...
, §32
...

Curiously enough, it is not used for basic_string (§23
...
Instead, the
standard-library string relies on char_traits (§36
...
2)
...
1
...
4)
...
2
...


25
...
5
...
For example:
template
Target to(Source arg)
// convert Source to Target
{
stringstream interpreter;
Target result;
if (!(interpreter << arg)
// write arg into stream
|| !(interpreter >> result)
// read result from stream
|| !(interpreter >> std::ws)
...
2);
auto x2 = to(1
...
2);
auto x4 = to(1
...
3
...
1)
...
3)
...
For conversion
among scalar numeric types, I tend to prefer narrow_cast<>() (§11
...


25
...
This doesn’t always make sense for someone
writing a template
...
’’ Many such design concerns can be addressed by providing
alternative definitions of the template and having the compiler choose between them based on the

Section 25
...
Such alternative definitions of a template are
called user-defined specializations, or simply user specializations
...

};
Vector vi;
Vector vps;
Vector vs;
Vector vpc;
Vector vpn;

In such code, most Vectors will be Vectors of some pointer type
...
2
...
3
...
That is, anyone who practices object-oriented programming and uses type-safe
containers (such as the standard-library containers) will end up with a lot of containers of pointers
...
This is usually good for run-time performance, but unless care is taken, it leads to code bloat
in critical cases such as the Vector example
...
Containers of pointers can share a single implementation
...
First, we define a version (a specialization) of
Vector for pointers to void:
template<>
class Vector {
// complete specialization
void∗∗ p;
//
...

Another use would be to implement unique_ptr based on a single shared implementation class
storing a void∗
...
The template arguments for which the specialization is to be used are specified in <>
brackets after the name
...


732

Specialization

Chapter 25

The Vector is a complete specialization
...

};

The specialization pattern after the name says that this specialization is to be used for every
pointer type; that is, this definition is to be used for every Vector with a template argument that can
be expressed as T∗
...

Note that when a partial specialization is used, a template parameter is deduced from the specialization pattern; the template parameter is not simply the actual template argument
...

Given this partial specialization of Vector, we have a shared implementation for all Vectors of
pointers
...

It is important that this refinement of the implementation of Vector be achieved without affecting the interface presented to users
...
Naturally, we could have given the general Vector
and the Vector of pointers different names
...

In this case, it is much better to hide the crucial implementation details behind a common interface
...
People who do not use a
technique like this (in C++ or in other languages with similar facilities for type parameterization)
have found that replicated code can cost megabytes of code space even in moderately sized programs
...
Using a single specialization

Section 25
...

Some compilers are getting smart enough to perform this particular optimization without help
from the programmer, but the technique is generally applicable and useful
...
In the context of C++, it was first documented in the
original template paper [Stroustrup,1988]
...
3
...
For example, the standard library complex uses specializations to adjust
the set of constructors and the argument types for important operations for important specializations (such as complex<float> and complex)
...
3
...
1)
looks like this:
template
class complex {
public:
complex(const T& re = T{}, const T& im = T{});
complex(const complex&);
// copy constructor
template
complex(const complex&);
// conversion from complex to complex
complex& operator=(const complex&);
complex& operator=(const T&);
complex& operator+=(const T&);
//
...

};

Note that the scalar assignment operators take reference arguments
...

complex<float>& operator= (float);
complex<float>& operator+=(float);
//
...

};

floats,

734

Specialization

Chapter 25

For complex, that same optimization applies
...
4
...
0, double im = 0
...

};

Note that these specialized constructors are constexpr, making complex a literal type
...
Also, this definition takes advantage of the knowledge that conversion from complex<float> to complex is safe (it never narrows), so that we
can have an implicit constructor from complex<float>
...


25
...
1
...
In that case, a specialization can even provide a representation that differs from that of the general template
...

};
template
class Matrix {
// specialization for N=1
T∗ elem;
int sz;
// number of elements
//
...

};

Section 25
...
2

The Primary Template

735

25
...
2 The Primary Template
When we have both a general definition of a template and specializations defining implementations
for specific sets of template arguments, we refer to the most general template as the primary template
...
14
...
5)
...

Only after a primary template has been chosen are specializations considered
...
For example:
template
class List {
//
...

};

// error : primary template after specialization

The critical information supplied by the primary template is the set of template parameters that the
user must supply to use it or any of its specializations
...
4), the primary template is where it belongs because concepts are something a user
cares about and must understand to use the template
...

};

For technical reasons (because the language doesn’t recognize constraints checks for what they
are), a constraints check needs to be replicated in every specialization
...

};

If used, the primary template must be defined somewhere (§23
...
If the primary template is never
instantiated, it need not be defined
...
If a user specializes a template, that specialization must be
in scope for every use of the template with the type for which it was specialized
...

};

736

Specialization

Chapter 25

List li;
template
class List {
//
...

It is essential that every use of a template for a given set of template arguments be implemented
by the same specialization
...
Clearly that would be disastrous, so a programmer must take care that explicit
specialization is consistent throughout a program
...

All specializations of a template must be declared in the same namespace as the primary template
...
7)
...


25
...
3 Order of Specialization
One specialization is more specialized than another if every argument list that matches its specialization pattern also matches the other, but not vice versa
...

The most specialized version will be preferred over the others in declarations of objects, pointers, etc
...
3)
...
5
...


25
...
4 Function Template Specialization
Specialization is also useful for template functions (§25
...
5
...
However, we can overload functions, so we see less specialization
...
14
...


Section 25
...
4
...
3
...
1 Specialization and Overloading
Consider the Shell sort from §12
...
5
...
A better definition would be:
template
bool less(T a, T b)
{
return a}
template
void sort(Vector& v)
{
const size_t n = v
...
We
now have less and swap as named entities for which we can provide improved versions
...

As written, sort() will not sort a Vector correctly because < will compare the two char∗s
...
Instead, we would like it to
compare the characters pointed to
...
3), the template<> prefix says that this is a specialization that can be specified
without a template parameter
...
Because the template argument can be deduced from the function argument list, we need not specify it explicitly
...
We can go further still
...
The standard-library swap() is correct for our use and has already
been optimized for every type that has efficient move operations
...

Specialization comes in handy when an irregularity of an argument type causes the general
algorithm to give an undesired result (such as less() for C-style strings)
...


25
...
4
...
3
...
1)
...

There are a few uses of function specializations
...

template
Iter my_algo(Iter p)
{
auto x = max_value>();
//
...
4
...

To get a roughly equivalent effect with overloading, we would have to pass a dummy (unused)
argument
...
3
...
2

Specialization That Is Not Overloading

739

int max2(int) { return INT_MAX; }
char max2(char) { return INT_MAX; }
template
Iter my_algo2(Iter p)
{
auto x = max2(Value_type{});
//
...
4 Advice
[1]
[2]
[3]

Use templates to improve type safety; §25
...

Use templates to raise the level of abstraction of code; §25
...

Use templates to provide flexible and efficient parameterization of types and algorithms;
§25
...

[4] Remember that value template arguments must be compile-time constants; §25
...
2
...
2
...

[6] Use default template arguments to provide simple notation for simple uses; §25
...
5
...
3
...
3
...
3
...
1
...
3
...
1
...

– H
...
Mencken







Introduction
Template Instantiation
When Is Instantiation Needed?; Manual Control of Instantiation
Name Binding
Dependent Names; Point-of-Definition Binding; Point-of-Instantiation Binding; Multiple
Instantiation Points; Templates and Namespaces; Overaggressive ADL; Names from Base
Classes
Advice

26
...
To produce impressive code quality, a compiler combines code (information) from
• the template definition and its lexical environment,
• the template arguments and their lexical environment, and
• the environment of the template’s use
...
The problem with
this is that code in a template definition isn’t as localized as we would prefer (all other things being
equal)
...

• Templates were introduced in §3
...
1 and §3
...
2
...

• Chapter 24 introduces generic programming and the key notion of concepts
...

• Chapter 27 discusses the relationship between templates and class hierarchies (supporting
generic and object-oriented programming)
...

• Chapter 29 presents a larger example of how the language facilities and programming techniques can be used in combination
...
2 Template Instantiation
Given a template definition and a use of that template, it is the implementation’s job to generate
correct code
...
2
...
From a template function and a set of template arguments, a
function needs to be generated
...

The generated classes and functions are called specializations
...
3),
we refer to generated specializations and explicit specializations, respectively
...

To use templates in nontrivial programs, a programmer must understand the basics of how
names used in a template definition are bound to declarations and how source code can be
organized (§23
...

By default, the compiler generates classes and functions from the templates used in accordance
with the name-binding rules (§26
...
That is, a programmer need not state explicitly which versions of which templates must be generated
...
Often, templates that the programmer hasn’t even heard of are used in the implementation of libraries, and sometimes templates that
the programmer does know of are used with unknown template argument types
...
4
...
4
...
In general, the set of generated
functions needed can be known only by recursive examination of the templates used in application
code libraries
...

On the other hand, it is sometimes important for a programmer to be able to state specifically
where code should be generated from a template (§26
...
2)
...


Section 26
...
1

When Is Instantiation Needed?

743

26
...
1 When Is Instantiation Needed?
It is necessary to generate a specialization of a class template only if the class’s definition is needed
(§iso
...
7
...
In particular, to declare a pointer to some class, the actual definition of a class is not
needed
...
A template class is not instantiated
unless its definition is actually needed
...

};
Link∗ pl;

// no instantiation of Link needed (yet)

Link lnk;

// now we need to instantiate Link

A place where a template is used defines a point of instantiation (§26
...
3)
...
By
‘‘used’’ we mean ‘‘called or had its address taken
...
This allows the programmer an
important degree of flexibility when defining a template class
...

void sort();
};
class Glob {
//
...

};
void f(List& lb, List& ls)
{
ls
...
use operations on lb, but not lb
...

}

Here, List::sort() is instantiated, but List::sort() isn’t
...
Had List::sort() been generated, we would have had to either add the operations needed by List::sort() to Glob, redefine sort()
so that it wasn’t a member of List (the better design anyway), or use some other container for Globs
...
2
...
However,
it does provide two mechanisms to help the user take control when needed
...

An explicit instantiation request (often simply called an explicit instantiation) is a declaration of a
specialization prefixed by the keyword template (not followed by <):
template class vector;
template int& vector::operator[](int);
template int convert(double);

// class
// member function
// nonmember function

A template declaration starts with template<, whereas plain template starts an instantiation request
...
5
...
For example:
template int convert(double);
template int convert(double);

// OK (redundant)
// OK

When a class template is explicitly instantiated, every member function is also instantiated
...
I
have seen examples in which bundling most template instantiations into a single compilation unit
cut the compile time from a number of hours to the equivalent number of minutes
...
It does not matter if such multiple specializations are user-defined (§25
...
2
...

However, a compiler is not required to diagnose multiple instantiations in separate compilation
units
...
However,
implementations are not required to be smart
...
The worst that will happen if they don’t is that their program won’t link;
there will be no silent changes of meaning
...
The obvious use is to have one explicit instantiation
for a specialization and use extern templates for its use in other translation units
...
2
...
For example:
#include "MyVector
...
2
...
use the vector in here
...
h"
template class MyVector;

// instantiate in this translation unit; use this point of instantiation

In addition to generating specializations for all members of a class, the explicit instantiation also
determines a single point of instantiation so that other points of instantiation (§26
...
3) can be
ignored
...


26
...
The reason is that a
template will be used to generate functions and classes based on unknown types and in unknown
contexts
...
The general
rule of avoiding global names as much as possible should be taken especially seriously in template
code
...
g
...
2
...
1
...
Use concepts to document dependencies on template arguments (§24
...

However, it is not unusual that some nonlocal names must be used to achieve the most elegant
formulation of a template
...
Sometimes, such functions can be class
members, but not always
...
Typical examples of
that are sort()’s calls to swap() and less() (§25
...
4)
...
When something needs to be nonlocal, prefer a named namespace to
the global scope
...

Operations with conventional names and semantics, such as +, ∗, [], and sort(), are another
source of nonlocal name use in a template definition
...
size(); i++)
t = t + v[i];
return t;
}

746

Instantiation

Chapter 26

//
...
h>
void f(std::vector& v)
{
Quad c = sum(v);
}

The innocent-looking template function sum() depends on several names that are not explicitly
specified in its definition, such as tracing, cerr, and the + operator
...
h>:
Quad operator+(Quad,Quad);

Importantly, nothing related to Quad is in scope when sum() is defined, and the writer of sum() cannot be assumed to know about class Quad
...

The process of finding the declaration for each name explicitly or implicitly used in a template
is called name binding
...
To help with this, the language separates names
used in a template definition into two categories:
[1] Dependent names: names that depend on a template parameter
...
3
...
In the sum() example, the definition of + can be found
in the instantiation context because it takes operands of the template argument type
...
Such names are
bound at the point of definition of the template (§26
...
2)
...

To be considered, both dependent and independent names must either be in scope at their point of
use or be found by argument-dependent lookup (ADL; §14
...
4)
...
For complete details, see
§iso
...
6
...
3
...
’’
Unfortunately, this doesn’t quite suffice; addition of Quads (§26
...


Section 26
...
1

Dependent Names

747

Consequently, a function call is said to depend on a template argument if and only if one of these
conditions holds:
[1] The type of the actual argument depends on a template parameter T according to the type
deduction rules (§23
...
2), for example, f(T(1)), f(t), f(g(t)), and f(&t), assuming that t is a T
...
5
...

Basically, the name of a called function is dependent if it is obviously dependent by looking at its
arguments or at its formal parameters
...
*/ };
void g(Quad);
int z = f(Quad{2});

// f’s g is bound to g(Quad)

A call that by coincidence has an argument that matches an actual template parameter type is not
dependent
...
*/ };
template
T ff(T a)
{
return gg(Quad{1});
}

// error : no gg() in scope and gg(Quad{1}) doesn’t depend on T

int gg(Quad);
int zz = ff(Quad{2});

Had gg(Quad{1}) been considered dependent, its meaning would have been most mysterious to a
reader of the template definition
...

This is exactly the same rule as for non-template function definitions (§26
...
2)
...
So, to use a
dependent name as a type, you have to say so, using the keyword typename
...

}

748

Instantiation

Chapter 26

We can avoid such awkward use of typename by introducing a type alias (§23
...
For example:
template
using Value_type = typename T::value_type;
template
void fct2(Container& c)
{
Value_type v1 = c[7];
//
...


// OK

(dot),

−>,

or

::

requires similar use of the keyword

template
...

};
template
void f(Alloc& all)
{
int∗ p1 = all
...
template get();
//
...

}

Compared to the use of typename to explicitly state that a name is assumed to name a type, the use
of template to explicitly state that a name is assumed to name a template is rare
...


26
...
2 Point-of-Definition Binding
When the compiler sees a template definition, it determines which names are dependent (§26
...
1)
...
3
...

Names that do not depend on a template argument are treated like names that are not in templates; they must be in scope (§6
...
4) at the point of definition
...
3
...

For example:
void g(double);
void g2(double);
template
int ff(T a)
{
g2(2);
// call g2(double);
g3(2);
// error: no g3() in scope
g(2);
// call g(double); g(int) is not in scope
//
...
The definition of g(int) comes too late to be considered – just as if ff()
had not been a template or if g had named a variable
...
3
...
3
...
This is called a point of instantiation for that specialization (§iso
...
6
...
1)
...
For a function template, that point is in the nearest global or namespace scope
enclosing its use, just after the declaration that contains that use
...
This is essential to ensure that the g() called in
f() is the global g(int) rather than the local g(double)
...
Ignoring local names is essential to prevent a lot of nasty
macro-like behavior
...
For example:
void g(int);
template
void f(T a)
{
g(a);
// g is bound at a point of instantiation
if (i) h(a−1);
// h is bound at a point of instantiation
}
void h(int i)
{
extern void g(double);
f(i);
}
// point of declaration for f

Here, having the point of instantiation after the definition of h() is necessary to allow the (indirectly
recursive) call h(a−1)
...

template
class Container {
vector v; // elements
//
...

};
// point of instantiation of Container
void f()
{
Container c; // point of use
c
...
3
...
sort() would have failed to find the definition
of Container
...
For example:
void fff()
{
struct S { int a,b; };
vector vs;
//
...

So why don’t we completely avoid nonlocal names in template definitions? That would certainly solve the technical problem with name lookup, but – as for ordinary function and class definitions – we want to be able to use ‘‘other functions and types’’ freely in our code
...
For example:
template
void print_sorted(vector& v)
{
sort(v
...
end());
for (const auto T& x : v)
cout << x << '\n';
}
void use(vector& vec)
{
//
...
begin(),v
...

using Iter = decltype(vs
...
To

752

Instantiation

Chapter 26

In this trivial case, there is a lot to be said for removing the dependence on the global name cout
...

Also, if the name-binding rules for templates were radically more restrictive than the rules for
non-template code, writing template code would be a completely separate skill from writing nontemplate code
...


26
...
4 Multiple Instantiation Points
A template specialization may be generated
• at any point of instantiation (§26
...
3),
• at any point subsequent to that in a translation unit,
• or in a translation unit specifically created for generating specializations
...

[2] At the end of a translation unit, generate all specializations needed for it
...

All three strategies have strengths and weaknesses, and combinations of these strategies are also
possible
...
A program is illegal if it is possible to construct two different meanings by choosing
different points of instantiation
...
For example:
void f(int);

// here, I take care of ints

namespace N {
class X { };
char g(X,int);
}
template
void ff(T t, double d)
{
f(d);
// f is bound to f(int)
return g(t,d); // g might be bound to g(X,int)
}
auto x1 = ff(N::X{},1
...
1 to 1

Namespace N {
double g(X,double);
}

// reopen N to take care of doubles

auto x2 = ff(N::X,2
...
3
...
For the first call, we could generate the specialization at
the initialization of x1 and get g(N::X,int) called
...
Consequently, the call
ff(N::X{},1
...

It is sloppy programming to call an overloaded function between two of its declarations
...
In this
particular case, a compiler could catch the ambiguity
...
An implementation is not obliged to catch problems of this kind
...


26
...
5 Templates and Namespaces
When a function is called, its declaration can be found even if it is not in scope, provided it is
declared in the same namespace as one of its arguments (§14
...
4)
...
The binding of dependent names is done (§iso
...
6
...
2) by looking at
[1] the names in scope at the point where the template is defined, plus
[2] the names in the namespace of an argument of a dependent call (§14
...
4)
...
*/ };
char f(A);
}
char f(int);
template
char g(T t)
{
return f(t);
}

// choose f() depending on what T is

char f(double);
char c1 = g(N::A());
char c2 = g(2);
char c3 = g(2
...
To generate a specialization for g(N::A), the implementation looks in namespace N for functions called f() and finds
N::f(N::A)
...
The f(double)
is not found because it is not in scope at the point of definition of the template (§iso
...
6
...
1), and
argument-dependent lookup (§14
...
4) does not find a global function that takes only arguments of
built-in types
...


754

Instantiation

Chapter 26

26
...
6 Overaggressive ADL
Argument-dependent lookup (often referred to as ADL) is very useful to avoid verbosity (§14
...
4)
...
As it is, the compiler notices that the first argument to << is an ostream defined in std
...

However, ADL can be ‘‘too aggressive’’ when combined with unconstrained templates
...

namespace User {
class Customer { /*
...

copy(x,y,false);// error
}
}

It would be a good guess that the author of User meant for User::alg() to call User::copy()
...
The compiler notices that Index really is a vector defined in std and looks
to see if a relevant function is available in std
...
On the other hand, the copy()
in User can be called only with a bool-to-int conversion
...

Using ADL to find fully general templates is arguably a language design error
...
The
standard says so, but the code does not
...
3, §24
...
2)
...


Section 26
...
6

Overaggressive ADL

755

template
Out copy(In p1, In p2, Out q)
{
static_assert(Input_iterator(), "copy(): In is not an input iterator");
static_assert(Output_iterator(), "copy(): Out is not an output iterator");
static_assert(Assignable,Value_type>(), "copy(): value type mismatch");
//
...
For example (§28
...

}

Unfortunately, many such templates are in libraries that a user cannot modify (e
...
, the standard
library)
...
If you need one, protecting it with a constraints check is often worthwhile
...
For example:
void User::algo(Index& x, Index& y)
{
User::copy(x,y,false);
// OK
//
...
2
...
For example:
template
void apply(const Range& r, Op f)
{
using std::begin;
using std::end;
for (auto& x : r)
f(x);
}

Now, the standard begin() and end() are in the overload set used by the range-for to traverse the
Range (unless Range has members begin() and end(); §9
...
1)
...
3
...
As for other names,
there are two distinct possibilities:
• The base class depends on a template argument
...

The latter case is simple and treated just like base classes in classes that are not templates
...

};

As ever, local names hide other names, so h(2) binds to X::h(int) and B::h(char) is never considered
...

That is, the global g() is never considered
...
Consider:
void g(int);
struct B {
void g(char);
void h(char);
};
template
class X : public T {
public:
void f()
{
g(2);
// call ::g(int)
}
//
...
3
...
f();
}

Why doesn’t g(2) call B::g(char) (as in the previous example)? Because g(2) isn’t dependent on the
template parameter T
...
If we want to have names from a dependent class considered, we must make the dependency clear
...
g
...

• Say that the name refers an object of this class (e
...
, this−>g)
...
g
...

For example:
void g(int);
void g2(int);
struct B {
using Type = int;
void g(char);
void g2(char)
};
template
class X : public T {
public:
typename T::Type m;
Type m2;

// OK
// error (no Type in scope)

using T::g2();

// bring T::g2() into scope

void f()
{
this−>g(2);
g(2);
g2(2);
}
//
...
f();
}

Only at the point of instantiation can we know if the argument used for the parameter T (here B) has
the required names
...
However, the alternative would be that a name in a template class would sometimes
bind to a base class member and sometimes to a global entity depending on the template argument
...
3)
...
However,
explicit qualifications help maintainers, so the initial author shouldn’t grumble too much about the
extra typing
...
For example:
template
class Matrix_base {
// memor y for matrices, operations of all elements
//
...

T∗ data() // return pointer to element storage
{
return this−>elem;
}
};

Here, the this−> qualification is required
...
4 Advice
[1]
[2]
[3]
[4]
[5]

Let the compiler/implementation generate specializations as needed; §26
...
1
...
2
...

Explicitly instantiate if you optimize the time needed to generate specializations; §26
...
2
...
3
...
3, §26
...
5
...
3
...

[7] Avoid fully general templates that can be found by ADL; §26
...
6
...
3
...

[9] Use using-declarations to limit the reach of ADL; §26
...
6
...
3
...


27
Templates and Hierarchies
Euclid’s and Beethoven’s Fifth;
knowing just one of them marks you as semi-educated
...
1 Introduction
Templates and derivation are mechanisms for building new types out of existing ones, for specifying interfaces, and generally for writing useful code that exploits various forms of commonality:
• A template class defines an interface
...
The source code implementing the
template (in the template definition) is identical for all parameter types
...
A specialization can add functionality to what
the primary template offers
...
The class’s own implementation and those of its derived
classes can (using virtual functions) be accessed through that interface
...
A derived class can add functionality to what the
base class offers
...
Since
both allow an algorithm to be expressed once and applied to a variety of types, people refer to both
as polymorphic (from Greek ‘‘many shapes’’)
...

The rough duality of the generic and object-oriented approaches can be deceptive
...
Generic programmers tend to focus on the design of algorithms with the concepts for template arguments providing an interface that can accommodate
many types (Chapter 24)
...
In many cases, the optimal design contains
elements of both
...
2
...

Generally, good object-oriented programming requires more foresight than good generic programming because all types in a hierarchy must explicitly share an interface defined as a base class
...
For example accumulate() (§3
...
2, §24
...
6
...


27
...
4
...
2
...
So:
• When do we choose to use a class template?
• When do we rely on a class hierarchy?
Consider these questions from a slightly simplified and abstract point of view:
template
class Ct {
// interface expressed in terms of the parameter
X mem;
public:
X f();
int g();
void h(X);
};
template<>
class Ct
{
A∗ mem;
public:
A f();
int g();
void h(A);
void k(int);
};

// specialization (for A)
// the representation can differ from that of the primar y template

// added functionality

Section 27
...
I used an explicit specialization (§23
...
3
...

The simpler case – without added functionality – is by far the more common
...

};
class Cx {
// interface expressed in terms of types in scope
X mem;
public:
virtual X& f();
virtual int g();
virtual void h(X&);
};
Class DA : public Cx {
public:
X& f();
int g();
void h(X&);
};

// derived class

Class DB : public Cx {
DB∗ p;
public:
X& f();
int g();
void h(X&);
void k(int);

// derived class
// representation can be more extensive than what the base provides

// added functionality

};
Cx& cxa {∗new DA}; // cxa is an interface to a DA
Cx& cxb {∗new DB}; // cxb is an interface to a DB

Given that, we can use f(), g(), and h() on the variables cxa and cxb, using the implementations of DA
and DB, respectively
...

In either case, we manipulate objects that share a common set of operations
...
To gain access to differing interfaces for derived classes through a base, we
must use some form of explicit casting (§22
...


762

Templates and Hierarchies

Chapter 27



If the implementations of generated or derived classes differ only through a parameter or
differ only in a few special cases, templates have an advantage
...

• If the actual types of objects used cannot be known at compile time, a class hierarchy is
essential
...
The base class provides a common interface
...
2
...

• If explicit use of free store (§11
...

• If run-time efficiency is at such a premium that inlining of operations is essential, templates
should be used (because effective use of hierarchy requires the use of pointers or references,
which inhibit inlining)
...
Expressing the interface in terms of
existing types that cannot vary for derived classes can be a struggle
...
g
...
g
...

The combination of templates and class hierarchies provides design choices and flexibility
beyond what either can offer by itself
...
2
...
3
...
3
...

It is not possible to have a virtual function template (§23
...
6
...


27
...
1 Generated Types
A class template is usefully understood as a specification of how particular types are to be created
...
Consequently, a class template is sometimes called a type generator
...
For example:
class Shape {
//
...

};

Given these declarations, people sometimes think that there must be an inheritance relationship
between set and set or at least between set and set
...
’’ The ‘‘therefore’’ part
of this argument doesn’t hold
...
For example:

Section 27
...
1

Generated Types

763

class Triangle : public Shape {
//
...

s
...

Nor should there be
...
If we allowed a set to be treated as a set, we could no longer maintain
that guarantee
...
If the
set could have been a set, the fundamental guarantee that a set contains
Circle∗s only would have been violated
...
That is, we could provide a conversion from const set to const setShape∗>
...

The combination of an array and a base class is particularly nasty because a built-in array does
not offer the type safety provided by containers
...
draw();
}
void user()
{
Circle image[10];
//
...

}

// Danger!

// looks innocent; it is not

// an image is composed of 10 Circles
// ‘‘maul’’ 10 Circles

How can we call maul() with image? First, image’s type is converted (decays) from Circle[] to CirNext, Circle∗ is converted to Shape∗
...
Similarly, implicit conversion of a
pointer to a derived class to a pointer to its base class is fundamental to object-oriented programming
...

cle∗
...
Then sizeof(Circle)>sizeof(Shape) and when we look at the layout of image we
find something like this:
user()
maul()

view:
view:

image[0]

image[1]

image[2]

image[3]

p[0] p[1] p[2] p[3]

When maul() tries to invoke a virtual function on p[1], there is no virtual function pointer where it is
expected and the call hopefully fails instantly
...

• Consider interfaces such as void f(T∗ p, int count) highly suspect; when T can be a base class
and count is an element count, trouble awaits
...
(dot) suspect when applied to something that is supposed to be run-time polymorphic unless it is obviously applied to a reference
...
2
...
2
...
However, for some templates we would like to express such a relationship
...
Member templates (§23
...
6) allow us to specify many such relationships where
desired
...

};

// copy constructor
// convert Ptr to Ptr

We would like to define the conversion operators to provide the inheritance relationships we are
accustomed to for built-in pointers for these user-defined Ptrs
...
In general, we need to define the conversion operator so that the Ptr to Ptr
conversion is accepted if and only if a T∗ can be assigned to a T2∗
...
2
...
Therefore, if T∗ can be implicitly converted into a T2∗, the Ptr to
Ptr conversion will work
...
If in doubt, use a named conversion
function, rather than a conversion operator
...

The template parameter lists of a template and one of its template members cannot be combined
...
4)
...
3 Hierarchies of Class Templates
Using object-oriented techniques, a base class is often used to provide a common interface to a set
of derived classes
...
For example, we could parameterize the classical shape example (§3
...
4) with types used to
provide an abstraction of the target output ‘‘device’’:
template
class Shape {
//
...

};

// questionable example

766

Templates and Hierarchies

Chapter 27

template
class Triangle : public Shape {
//
...

}

Something along this line is often the first idea (after seeing something like vector) that a programmer used to object-oriented programming considers
...

As written, this parameterized shape hierarchy is too verbose for real use
...
2
...
However, the verbosity is not the main problem
...
The ‘‘almost’’ comes because the compiler will suppress code generation for the definitions of unused non-virtual member functions of a class template
...
Because a graphics hierarchy is likely to have many derived classes, many member
functions, and many complicated functions, the result is likely to be massive code bloat
...
Parameterizing a huge class hierarchy with many virtual member functions is typically a poor idea
...
These parameters are an ‘‘implementation detail’’ that escaped into the interface – with likely serious performance implications
...
It is generally not a good idea to ‘‘overparameterize’’ (§23
...
6
...
If only a few member functions are affected by a parameter, try to make those function templates with that parameter
...

};

How to share the configuration information among different classes and different objects is a separate issue
...
One solution would be for configure() to
‘‘translate’’ the information in Color_scheme and Canvas into a standard set of configuration parameters (e
...
, a set of integers)
...


Section 27
...
1

Templates as Interfaces

767

27
...
1 Templates as Interfaces
A template class can be used to provide a flexible and type-safe interface to a common implementation
...
3 is a good example of this:
template
class Vector
: private Vector
{
//
...


27
...
2
...
2
...
That way, we can write common code without worrying about variations in
the implementations
...
2)
...
To compensate, we might pass the specialized information and operations to the base class as template arguments
...

The general problem addressed by the following two subsections is ‘‘How can we combine separately specified information into a single compact object with a well-specified interface?’’ This is
a fundamental question and the solutions are of general importance
...
4
...
Since we are providing a library to be used by
many different users, we can’t build the type of the user’s (application’s) data into our tree nodes
...
But the
virtual function calls (or equivalently, run-time resolved and checked solutions) are relatively expensive, and our interface to the user’s data is not expressed in terms of the user’s
type, so we still need to use casts to access it
...
But that could double the number of allocations, add many (potentially expensive) pointer dereferences, and add the space overhead of a pointer in each node
...
That cast can’t be type
checked
...
That would solve the type-checking problem, but that combines the cost and
inconvenience of the previous two approaches
...

}
//
...

};

// use derived class as part of its own base

Here, we pass the derived class Node as a template argument to its own base (Node_base)
...
For example, a Node will look roughly
equivalent to this:
struct Node_base_double {
double val;
Node_base_double∗ left_child;
Node_base_double∗ right_child;
};

Unfortunately, with this design, a user has to be aware of Node_base’s operations and the structure
of the resulting tree
...
4
...
add_left(p);
else
root
...
Typically, we would
like to let the tree take care of that by implementing a tree-balancing algorithm
...

How do we add a balancer to our design? We could hardwire the balancing strategy into
Node_base and let Node_base ‘‘peek’’ at the user data
...
That way, the Node_base operations can simply use <:
template
struct Node_base {
static_assert(Totally_ordered(), "Node_base: N must have a <");
N∗ left_child;
N∗ right_child;
Balancing_info bal;
Node_base();
void insert(N& n)
{
if (n//
...

else
//
...

}
//
...
In fact, the more information about nodes we build into the Node_base, the simpler the implementation becomes
...
However, doing so doesn’t address the fundamental question we are trying to
address here: how to combine information from several separately specified sources
...

So let us assume that the user will want to manipulate Nodes (e
...
, move a node from one tree to
another), so that we can’t simply store user data into an anonymous node
...
These assumptions force us to face the fundamental question
...
However, Node doesn’t need to
use the balancer, so it just passes it on to Node_base:

770

Templates and Hierarchies

Chapter 27

template
struct Search_node : public Node_base, Balance>
{
Val val;
// user data
search_node(Val v): val(v) {}
};

is mentioned twice here because it is part of the node type and because Node_base needs to
make an object of type Balance:

Balance

template
struct Node_base : Balance {
N∗ left_child;
N∗ right_child;
Node_base();
void insert(N& n)
{
if (this−>compare(n,left_child))
//
...

else
//
...

}
//
...
However, some important balancers require no per-node data, so by making Balance a base, I benefit from the empty-base
optimization
...
1
...
Also, this design is with
minor stylistic differences that of a real binary tree framework [Austern,2003]
...
insert(∗new My_node{x});
}

Section 27
...
1

Composing Data Structures

771

The layout of a node is compact, and we can easily inline all performance-critical functions
...

This elaboration delivers a performance advantage compared to every approach that introduces a
void∗ into the data structure or function interfaces
...
Choosing a low-level (C-style) programming technique in the key parts of
a balanced binary tree implementation implies a significant run-time cost
...

};
template
struct Search_node
: public Node_base, Balance>
{
//
...
The alternative is
to make the balancer an implicit argument in the form of an associated type (a member type of
Search_node):
template
struct Node_base : N::balance_type {
//
...

};

This technique is heavily used in the standard library to minimize explicit template arguments
...
It was mentioned in the ARM (1989)
and is sometimes referred to as the Barton-Nackman trick after an early use in mathematical software [Barton,1994]
...


27
...
2 Linearizing Class Hierarchies
The Search_node example from §27
...
1 uses its template to compress its representation and to
avoid using void∗
...
In particular, many programs that
deal with trees rely on it for type safety and performance
...
It uses template parameters as base classes extensively, both as an
implementation aid (implementation inheritance) and to provide abstract interfaces in the classical
object-oriented way (interface inheritance)
...

The users see a hierarchy of abstract classes providing perfect encapsulation and clean functional interfaces representing the semantics of a program
...

In addition, there is a parallel hierarchy of concrete classes providing compact and efficient
implementations of the classes in the interface hierarchy:
impl::Var −> impl::Decl −> impl::Stmt −> impl::Expr −> impl::Node

In all, there are about 80 leaf classes (such as Var, If_stmt, and Multiply) and about 20 generalizations
(such as Decl, Unary, and impl::Stmt)
...
In addition, programs were seriously slowed down by the
many indirections to access the many virtual bases in each object (§21
...
5)
...
4
...
2
...
3
...

I will show how that is done
...
Starting from the bottom, a Node holds data used to optimize traversal and Node type identification (the code_category) and to ease storage of IPR graphs in files (the node_id)
...
What a user will know is that every node
in an IPR graph has a unique base of type Node and that this can be used to implement operations
using the visitor pattern [Gamma,1994] (§22
...
It also has a pure virtual function, so it cannot be instantiated except as a base class
...

A statement (Stmt) is an Expr that has a source file location and can be annotated with various
information:
struct ipr::Stmt : Expr {
virtual const Unit_location& unit_location() const = 0;
// line in file
virtual const Source_location& source_location() const = 0; // file
virtual const Sequence& annotation() const = 0;
protected:
Stmt(Category_code c) : Expr(c) { }
};

A declaration (Decl) is a Stmt that introduces a name:
struct ipr::Decl : Stmt {
enum Specifier { /* storage class, vir tual, access control, etc
...

protected:
Decl(Category_code c) : Stmt(c) { }
};

As you might expect, Decl is one of the central notions when it comes to representing C++ code
...

Finally, we can define a class to represent a variable (Var) as a leaf class (most derived class) of
our interface hierarchy:

Section 27
...
2

Linearizing Class Hierarchies

775

struct ipr::Var : Category {
};

Basically, Category is a notational aid with the effect of deriving Var from Decl and giving the Category_code used to optimize Node type identification:
template
struct Category : T {
protected:
Category() : T(Cat) { }
};

Every data member is a Var
...

Compared to representations you find in compilers, this interface is tiny
...
Note that it is a
single hierarchy with no virtual base classes
...
However, implementing this simply, efficiently, and maintainably is not easy, and IPR’s solution is certainly not what an experienced object-oriented designer would first think of
...

For example:
template
struct impl::Node : T {
using Interface = T; // make the template argument type available to users
void accept(ipr::Visitor& v) const override { v
...
In particular, the impl nodes must provide the necessary data members and override the abstract virtual functions in the ipr nodes
...

Now, we can proceed to provide implementation classes for the rest of the ipr interface classes:
template
struct impl::Expr : impl::Node {
const ipr::Type∗ constraint;
// constraint is the type of the expression
Expr() : constraint(0) { }
const ipr::Type& type() const override { return ∗util::check(constraint); }
};

If the Interface argument is an ipr::Expr or any class derived from ipr::Expr, then impl::Expr is an
implementation for ipr::Expr
...
Since ipr::Expr is derived from ipr::Node,
this implies that impl::Node gets the ipr::Node base class that it needs
...
We can proceed in this manner:

776

Templates and Hierarchies

Chapter 27

template
struct impl::Stmt : S {
ipr::Unit_location unit_locus;
// logical position in translation unit
ipr::Source_location src_locus;
// source file, line, and column
ref_sequence notes;
const ipr::Unit_location& unit_location() const override { return unit_locus; }
const ipr::Source_location& source_location() const override { return src_locus; }
const ipr::Sequence& annotation() const override { return notes; }
};

That is, impl:Stmt provides the three data items needed to implement ipr::Stmt’s interface and overrides ipr::Stmt’s three virtual functions to do so
...
The implementation
of Var is an example of generic programming, but its use is classical object-oriented programming
...
This expressive power can
lead to confusion for beginners and occasionally even for experienced programmers when faced
with a new application area
...
The extensibility offered by class hierarchies and virtual functions is not compromised
...
5

Advice

777

27
...
1
...
1
...
1
...
2
...
2
...
2
...
2
...
2
...
2
...
2
...

There is no default relation between two classes generated from the same template; §27
...
1
...
2
...

Do not naively templatize large class hierarchies; §27
...

A template can be used to provide a type-safe interface to a single (weakly typed) implementation; §27
...
1
...
4
...

Templates can be used to linearize a class hierarchy (minimizing space and access time);
§27
...
2
...

– John Steinbeck










Introduction
Type Functions
Type Aliases; Type Predicates; Selecting a Function; Traits
Control Structures
Selection; Iteration and Recursion; When to Use Metaprogramming
Conditional Definition: Enable_if
Use of Enable_if; Implementing Enable_if; Enable_if and Concepts; More Enable_if Examples
A Compile-Time List: Tuple
A Simple Output Function; Element Access; make_tuple
Variadic Templates
A Type-Safe printf(); Technical Details; Forwarding; The Standard-Library tuple
SI Units Example
Units; Quantitys; Unit Literals; Utility Functions
Advice

28
...
I find it useful to think of templates as generators: they are used to make
classes and functions
...
Variations of this idea have been
called two-level programming, multilevel programming, generative programming, and – more commonly – template metaprogramming
...
g
...

• Improved run-time performance: We can compute values at compile time and select functions to be called at run time
...
g
...
In
particular, by taking advantage of the type system, we can dramatically improve the opportunities for inlining
...
4
...
5), we make better use of memory with positive effects on both the amount of data we
can handle and the execution speed
...

They provide arithmetic, selection, and recursion
...
That is, templates and their template instantiation mechanism are Turing complete
...
The C++
compile-time mechanisms provide a pure functional programming language: You can create values
of various types, but there are no variables, assignments, increment operators, etc
...
B)
...

Where should we draw the line between generic programming and template metaprogramming?
The extreme positions are:
• It is all template metaprogramming: after all, any use of compile-time parameterization
implies instantiation that generates ‘‘ordinary code
...

Both of these positions are useless because they basically define generic programming and template
metaprogramming as synonyms
...
A distinction
helps us decide between alternative approaches to problems and to focus on what is important for a
given problem
...
I am not using my programming skills for the compile-time part of my program
...
3)
...
2
...

In contrast, metaprogramming is programming
...
Metaprogramming is primarily a set of implementation
techniques
...
4) or addition of units (§28
...
1)
[3] Computation using explicit compile-time tests, for example, a compile-time if (§28
...

[4] Computation using compile-time iteration (in the form of recursion; §28
...
2)
...
1

Introduction

781

The ordering indicates the level of complexity, with implications for the difficulty of the task, the
difficulty of debugging, and the likelihood of error
...
Note that I don’t say
‘‘template metaprogramming’’ because the computation may be done using constexpr functions
...
2
...
2
...

Generic programming usually falls into the first, ‘‘no computation’’ category, but it is quite possible to support generic programming using metaprogramming techniques
...

Once we use (meta)programming as part of an interface, the possibility of programming errors
creeps in
...

Generic programming focuses on interface specification, whereas metaprogramming is programming, usually with types as the values
...
As ever, we have to apply common sense
...
Many standard-library
components, such as function (§33
...
3), thread (§5
...
1, §42
...
2), and tuple (§34
...
4
...

This chapter explores the basic metaprogramming techniques and presents the basic building
blocks of metaprograms
...


28
...
For example, sizeof(T) is a built-in type function that given a type argument T
returns the size of an object (measured in chars; §6
...
8)
...
In fact, most don’t
...
Similarly, the standard-library convention is that a type function that returns a type does so by a member called type
...
4
...
For example:

782

Metaprogramming

Chapter 28

template
struct Array_type {
using type = T;
static const int dim = N;
//
...
I just used
it as an excuse to show how to write a simple multi-argument, multi-return-value type function
...
That is, they can only take arguments (types and values) that are known at compile time and produce results (types and values) that can be used at compile time
...
For
example, here is a type function that returns an integer type of the appropriate number of bytes:
template
struct Integer {
using Error = void;
using type = Select;
};
typename Integer<4>::type i4 = 8; // 4-byte integer
typename Integer<1>::type i1 = 9; // 1-byte integer
Select is defined and explained in §28
...
1
...
It is of course possible to write templates that take values only and produce values only
...
Also, constexpr functions
(§12
...
6) are usually a better way of expressing compile-time computations on values
...
2
...
4, §28
...
2)?
So, C++ type functions are mostly templates
...
They are the backbone of metaprogramming
...
2

Type Functions

783

The standard-library template conditional is a compile-time selector between two alternatives
...
§28
...
1
...
In
this case, Obj_holder’s type is defined to be Scoped if an object of X is small and On_heap
if it is large
...

∗v1 = 7
...
9; // On_heap provides pointer-like access (* and [])
//
...
For example, the C++ standard contains the following
comment in its definition of the function type (§33
...
3) for holding function-like entities: ‘‘Implementations are encouraged to avoid the use of dynamically allocated memory for small callable
objects, for example, where f’s target is an object holding only a pointer or reference to an object
and a member function pointer’’ (§iso
...
8
...
2
...
It would be hard to follow that advice without
something like Obj_holder
...

Both On_heap and Scoped can be used as members as well as local variables
...

§28
...

On_heap

28
...
1 Type Aliases
Note how the implementation details of Obj_holder (as for Int) shine through when we use typename
and ::type to extract the member type
...
I consider it insufferable
...
By introducing a template alias (§23
...

For example:
template
using Holder = typename Obj_holder::type;
void f2()
{
Holder v1;
// the double goes on the stack
Holder> v2;
// the array goes on the free store
//
...
7;
// Scoped provides pointer-like access (* and [])
v2[77] = 9
...

}

Except when explaining an implementation or what the standard specifically offers, I use such type
aliases systematically
...
4
...


28
...
1
...
If only one of
the alternatives is supposed to be a valid type, we should not use an alias
...
2
...
1

When Not to Use an Alias

785

if (p) {
p−>f(7);
//
...
We are using the test to see if
valid
...
For example:

p

is

conditional<
is_integral::value,
make_unsigned,
Error
>::type

Here, we test if T is an integral type (using the std::is_integral type predicate) and make the
unsigned variant of that type if it is (using the std::make_unsigned type function)
...

Had we written Make_unsigned meaning
typename make_unsigned::type

and tried to use it for a nonintegral type, say std::string, we would have tried to make a nonexistent
type (make_unsigned::type)
...

In the rare cases where we can’t use aliases consistently to hide ::type, we can fall back on the
more explicit, implementation-oriented ::type style
...
> class F, typename
...
>;

This uses a template template argument (§25
...
4) and variadic templates (§28
...

Independently of which solution we choose to avoid the undesired instantiation, this is the kind
of expert territory that I enter only with some trepidation
...
2
...
If you want to write functions that take arguments that are types, it seems obvious that you’ll like to ask questions about the arguments’ types
...
e
...
4
...
For example:

786

Metaprogramming

template
void copy(T∗ p, const T∗ q, int n)
{
if (std::is_pod::value)
memcpy(p,q,n);
else
for (int i=0; i!=n; ++i)
p[i] = q[i];
}

Chapter 28

// use optimized memory copy

// copy individual values

Here, we try to optimize the copy by using the (supposedly optimal) standard-library function memcpy() when we can treat the objects as ‘‘plain old data’’ (POD; §8
...
6)
...
We determine whether the template argument
type is a POD by the standard-library type predicate is_pod
...
This standard-library convention is similar to the way type functions present their result as a
member type
...
4
...
Since
the rules for being a POD are tricky, is_pod is most likely a compiler intrinsic rather than implemented in the library as C++ code
...

}

Fortunately, the standard supports that for all standard-library type predicates
...

For example:
template
void do_something()
{
Conditional(),On_heap,Scoped) x;
//
...
14
...

My solution is to add functions to provide the conventional notation in all contexts:
template
constexpr bool Is_pod()
{
return std::is_pod::value;
}

Section 28
...
2

Type Predicates

787

I capitalize the names of these type functions to avoid confusion with the standard-library versions
...

We can define our own type predicates
...
Examples are is_integral, is_pointer, is_empty, is_polymorphic, and is_move_assignable (§35
...
1)
...
For example, we can define a type function to determine whether a
class has a member of a given name and of an appropriate type (§28
...
4)
...
In particular, this is
how we represent relations between two types, such as is_same, is_base_of, and is_convertible
...

I use Is_∗ constexpr functions to support the usual () calling syntax for all of these is_∗ functions
...
2
...
For example:
struct X { // write X
void operator()(int x) { cout <<"X" << x << "!"; }
//
...

};
void f()
{
Conditional<(sizeof(int)>4),X,Y>{}(7);

// make an X or a Y and call it

using Z = Conditional<(Is_polymorphic()),X,Y>;
Z zz;
// make an X or a Y
zz(7);
// call an X or a Y
}

As shown, a selected function object type can be used immediately or ‘‘remembered’’ for later use
...

Conditional is a mechanism for compile-time programming
...
Note the parentheses around sizeof(int)>4; without those,
we would have gotten a syntax error because the compiler would have interpreted the > as the end
of the template argument list
...
Also, I sometimes use parentheses around conditions for readability
...
2
...
A trait is used to associate properties with a type
...
1
...

The standard library provides allocator_traits (§34
...
2), char_traits (§36
...
2), iterator_traits
(§33
...
3), regex_traits (§37
...
4
...
In addition, it provides time_traits (§35
...
4)
and type_traits (§35
...
1), which confusingly are simple type functions
...

}

This is a most useful and powerful technique, but:
• It is verbose
...

• It exposes implementation details to users
...

Consequently, I prefer to use simple type functions:
template
using Value_type = typename std::iterator_trait::value_type;
template
using Difference_type = typename std::iterator_trait::difference_type;

Section 28
...
4

Traits

789

template
using Iterator_category= typename std::iterator_trait::iterator_category;

The example cleans up nicely:
template
Iter search(Iter p, iter q, Value_type val)
{
Difference_type m = q−p;
//
...
Consider how to write the previous example without
any mention of traits or other type functions:
template
Iter search(Iter p, iter q, Val val)
{
auto x = ∗p;
auto m = q−p;
using value_type = decltype(∗p);
using difference_type = decltype(q−p);

// if we don’t need to name *p’s type
// if we don’t need to name q-p’s type
// if we want to name *p’s type
// if we want to name q-p’s type

//
...
Also, auto and decltype are new in C++11, so older code could not have
been written this way
...
For that, a trait (or an equivalent) is indispensable for non-intrusively adding
type names needed for generic programming or metaprogramming
...
Don’t blindly define traits for everything ‘‘just in case
...
3 Control Structures
To do general computation at compile time, we need selection and recursion
...
3
...
4), I use:
• Conditional: a way of choosing between two types (an alias for std::conditional)
• Select: a way of choosing among several types (defined in §28
...
1
...
If you want to choose among values, ?: is sufficient; Conditional

790

Metaprogramming

Chapter 28

and Select are for selecting types
...
4
...
2
...


28
...
1
...
2
...
3
...
1) simply defines its type to be T (the first template parameter after
the condition)
...
For example:
typename conditional<(std::is_polymorphic::value),X,Y>::type z;

Obviously, the syntax leaves a bit to be desired (§28
...
2), but the underlying logic is beautiful
...
3)
...
3
...
1) to all but
a single terminating case (§28
...
This form of selection is completely compile-time and doesn’t
cost a byte or a cycle at run time
...


28
...
1
...
Run Time
Looking at something like
Conditional<(std::is_polymorphic::value),X,Y> z;

for the first time, it is not uncommon for people to think, ‘‘Why don’t we just write a normal if?’’
Consider having to choose between two alternatives, Square and Cube:

Section 28
...
1
...
Run Time

791

struct Square {
constexpr int operator()(int i) { return i∗i; }
};
struct Cube {
constexpr int operator()(int i) { return i∗i∗i; }
};

We might try the familiar if-statement:
if (My_cond())
using Type = Square;
else
using Type = Cube;
Type x;

// error : declaration as if-statement branch
// error : declaration as if-statement branch

// error: Type is not in scope

A declaration cannot be the only statement of a branch of an if-statement (§6
...
4, §9
...
1), so this
will not work even though My_cond() is computed at compile time
...

Let us try an example that doesn’t involve defining a variable:
Conditional(),Square,Cube>{}(99);

// invoke Square{}(99) or Cube{}(99)

That is, select a type, construct a default object of that type, and call it
...
Using ‘‘conventional control structures,’’ this would become:
((My_cond())?Square:Cube){}(99);

This example doesn’t work because Square{}(99) and Cube{}(99) do not yield types, rather than values of types that are compatible in a conditional expression (§11
...
3)
...
The restriction to compatible types is
often unacceptable in metaprogramming because we need to choose between types that are not
explicitly related
...
3
...
3 Selecting among Several Types
Selecting among N alternatives is very similar to choosing between two
...
I chose zero-based numbering to match the rest of C++
...
We don’t really want to pick a maximum number of
alternatives (here, four), but that problem can be addressed using variadic templates (§28
...
The
result of picking a nonexisting alternative is to use the primary (general) template
...

A realistic use would be to select the type for a function returning the Nth element of a tuple:
template
Select get(Tuple& t);
// see §28
...
2
auto x = get<2>(t); // assume that t is a Tuple

Here, the type of x will be whatever T3 is for the Tuple called t
...

Using variadic templates (§28
...
Cases>
struct select;

// general case; never instantiated

template ...
> :select ...
3
...
3

template ...
> {
using type = T;
};

Selecting among Several Types

793

// final case: N==0

template ...
>::type;

28
...
2 Iteration and Recursion
The basic techniques for calculating a value at compile time can be illustrated by a factorial function template:
template
constexpr int fac()
{
return N∗fac();
}}
template<>
constexpr int fac<1>()
{
return 1;
}
constexpr int x5 = fac<5>();

The factorial is implemented using recursion, rather than using a loop
...
4), that makes sense
...

Note the absence of a condition: there is no N==1 or N<2 test
...
In template metaprogramming (as in
functional programming), the idiomatic way of working your way through a sequence of values is
to recurse until you reach a terminating specialization
...
The
non-template version is marginally easier for a compiler to handle
...

The constexpr version can be used for both compile-time and run-time evaluation
...


794

Metaprogramming

Chapter 28

28
...
2
...
For example, the factorial program becomes:
template
struct Fac {
static const int value = N∗Fac::value;
};
template<>
struct Fac<1> {
static const int value = 1;
};
constexpr int x7 = Fac<7>::value;

For a more realistic example, see §28
...
2
...
3
...
The question remains: Why would you want to? We should use
these techniques if and when they yield cleaner, better-performing, and easier-to-maintain code
than alternative techniques
...
Nontrivial uses
of templates can also impact compile times
...
Worse still, so
may the programmer who gets to maintain your code
...
When the improvements
are significant and the code maintainable, these are good – sometimes even compelling –
reasons
...
Obviously,
that is to be avoided
...
6) to hide ‘‘details’’ that have become too ugly to deal with
directly
...


Section 28
...
3

When to Use Metaprogramming

795

Similarly, a more complex condition would almost equalize the number of characters used
...

That exposes the template implementation technique
...

However, if many people need to collaborate and programs get large, a bit of verbosity is preferable
to a divergence of notations
...
That ::type represents a significant difference: conditional selects between types; it does not directly alter control flow
...
The IF macro hides an
essential aspect of its function
...

In this case, the problems of verbosity, of the implementation details leaking out, and of poor
naming are easily handled by a type alias (Conditional; §28
...
1)
...
Prefer systematic techniques, such as specialization and the use of aliases, to macro hackery
...
2
...

Alternatively, we can look at the fundamental complexity of what we are trying to do:
[1] Does it require explicit tests?
[2] Does it require recursion?
[3] Can we write concepts (§24
...
Maybe some form of encapsulation is possible?
Remember that complexities of a template implementation become visible to users (‘‘leak out’’)
whenever an instantiation fails
...


28
...
For example:
template
class Smart_pointer {
//
...

}

// return reference to whole object
// select a member (for classes only)

If T is a class, we should provide operator−>(), but if T is a built-in type, we simply cannot do so
(with the usual semantics)
...
’’ We might try the obvious:

796

Metaprogramming

template
class Smart_pointer {
//
...

}

Chapter 28

// return reference to whole object
// syntax error

However, that does not work
...
But, as with Conditional and Select (§28
...
1), there is a way
...
The standard
library (in ) provides enable_if for that
...

T& operator∗();
Enable_if(),T>∗ operator−>();
//
...
If Enable_if’s
condition evaluates to false, the whole function declaration of which it is part is completely
ignored
...

Given the definition of Smart_pointer using Enable_if, we get:
void f(Smart_pointer p, Smart_pointer> q)
{
auto d0 = ∗p;
// OK
auto c0 = ∗q;
// OK
auto d1 = q−>real();
// OK
auto d2 = p−>real();
// error : p doesn’t point to a class object
//
...
The standard library provides many examples of conditional definition,
such as Alloc::size_type (§34
...
2) and pair being movable if both of their elements are (§34
...
4
...

The language itself defines −> only for pointers to class objects (§8
...


Section 28
...

• If we conditionally declare operator−>() using Enable_if, if we use −> on a smart_ptr,
we get a ‘‘Smart_ptr::operator−>() not defined’’ error at the point of use of
Smart_ptr::operator−>()
...

We have moved the error detection and reporting from the implementation of
smart_pointer::operator−>() to its declaration
...

In general, it is preferable to specify templates precisely so as to detect errors early rather than relying on bad instantiations being caught
...
3): it allows a more precise specification of the requirements of a template
...
4
...
Consider:

enable_if

is pretty ideal
...
However, what is actually expressed is
pretty close to the minimal ideal:
declare_if (Is_class()) T∗ operator−>();

// not C++

However, C++ does not have a declare_if construct for selecting declarations
...
However,
some declarations do not have a return type
...

};

This looks innocent enough, but the constructor taking a number of elements wrecks its usual
havoc
...
The problem is that I ‘‘forgot’’ to tell the compiler that the Iter type should be an iterator
...

};

That (unused) default template argument will be instantiated because we certainly can’t deduce that
unused template parameter
...
4
...

I introduced the Enable_if as a default template argument because that is the most general solution
...
However, in this
case, we could alternatively apply it to the constructor argument type:
template
class vector {
public:
vector(size_t n, const T& val);

// n elements of type T with value val

template
vector(Enable_if(),Iter>> b, Iter e);
//
...
The implementation and use of Enable_if rely on a detail in the
rules for overloading function templates (§23
...
3
...
Consequently, it cannot be used to control
declarations of classes, variables, or non-template functions
...

}

// error : tmp is not a function
// error : tmp is not a function

For tmp, using Holder (§28
...
4
...
4
...

For a language-technical explanation of how these simple declarations become useful as a fundamental construct see §23
...
3
...


28
...
3 Enable_if and Concepts
We can use Enable_if for a wide variety of predicates, including many tests of type properties
(§28
...
1
...
Concepts are among the most general and useful predicates we have
...
For example:
template
Enable_if()> fct(T∗,T∗);

// optimized implementation

template
Enable_if()> fct(T∗,T∗);

// nonoptimized implementation

Note that Enable_if defaults to void, so fct() is a void function
...
size()==0 || vc
...
front(),&vi
...
front(),&vc
...


int

but not for a

complex
...
4
...
For many of the standard operations, such as constructors and assignments, the standard library provides a type property predicate, such as is_copy_assignable and
is_default_constructible (§35
...
1)
...
Consider the

800

Metaprogramming

Chapter 28

question ‘‘Can we call f(x) if x is of type X?’’ Defining has_f to answer that question gives an
opportunity to demonstrate some of the techniques used and some of the scaffolding/boilerplate
code provided internally in many template metaprogramming libraries (including parts of the standard library)
...
5
...
2)
...
Obviously, std::true_type and
std::false_type are types that represent the values true and false, respectively:
std::true_type::value == true
std::false_type::value == false

We use substitution_succeeded to define the type functions we really want
...
For that, we can define has_f:
template
struct has_f
: substitution_succeeded::type>
{ };

So, if get_f_result yields a proper type (presumably the return type of a call of f), has_f::value is
true_type::value, which is true
...

So far, so good, but how do we get get_f_result to be substitution_failure if somehow f(x)
doesn’t compile for a value x of type X? The definition that achieves that looks innocent enough:
template
struct get_f_result {
private:
template
static auto check(X const& x) −> decltype(f(x));
static substitution_failure check(
...
Obviously, that
won’t compile unless we can call f(x)
...
In that
case, because substitution failure is not an error (SFINAE; §23
...
3
...
And, yes, this elaborate piece of trickery
fails if our function f was declared to return a substitution_failure
...
4
...

We managed to turn what looked like a type error into the value false
...
Given the scaffolding
code, we just have to provide conventional syntax:
template
constexpr bool Has_f()
{
return has_f::value;
}

Now, we can write:
template
class X {
//
...

f(t);
//
...

};

has a member use_f() if and only if f(t) can be called for a T value t
...

Given the technique used to define Has_f, we can define Has_foo for any operation or member
foo we can think of
...
This can get repetitive but is
not difficult
...
For example, we can define a Has_not_equals() type
function to check if != is available and use it like this:
template
Enable_if(),Iter> find(Iter first, Iter last, Val v)
{
while (first!=last && !(∗first==v))
++first;
return first;
}

802

Metaprogramming

Chapter 28

template
Enable_if(),Iter> find(Iter first, Iter last, Val v)
{
while (!(first==last) && !(∗first==v))
++first;
return first;
}

Such ad hoc overloading easily gets messy and unmanageable
...
Consequently, I recommend relying on the more structured standard overloading rules (§12
...
1) and
specialization rules (§25
...
For example:
template
auto operator!=(const T& a, const T& b) −> decltype(!(a==b))
{
return !(a==b);
}

The rules ensure that if a specific != has already been defined for a type T (as a template or as a nontemplate function), this definition will not be instantiated
...

Similarly, we can conditionally define >, <=, >=, etc
...


28
...
I will define a Tuple with an associated access operation and an output operation
...
The more elegant and
more general std::tuple is presented in §28
...
4 and §34
...
4
...

The idea is to allow code like this:
Tuple x {1
...
1, 42, 'a'};
42

The definition of Tuple is fundamentally simple:
template
struct Tuple : Tuple { // layout: {T2,T3,T4} before T1
T1 x;
using Base = Tuple;

Section 28
...

We construct a Tuple of four elements with a constructor that takes four values (potentially of
four different types)
...

Manipulation of the tail of a Tuple – that is of the base class of the Tuple – is important and common in the implementation of the Tuple
...

Obviously, this definition handles only tuples that really have four elements
...
Tuples with fewer than four elements are defined as specializations:
template<>
struct Tuple<> { Tuple() {} };
template
struct Tuple : Tuple<> {
T1 x;

// 0-tuple

// 1-tuple

using Base = Tuple<>;
Base∗ base() { return static_cast(this); }
const Base∗ base() const { return static_cast(this); }
Tuple(const T1& t1) :Base{}, x{t1} { }
};
template
struct Tuple : Tuple {
T1 x;

// 2-tuple, layout: T2 before T1

using Base = Tuple;
Base∗ base() { return static_cast(this); }
const Base∗ base() const { return static_cast(this); }
Tuple(const T1& t1, const T2& t2) :Base{t2}, x{t1} { }
};
template
struct Tuple : Tuple {
// 3-tuple, layout: {T2,T3} before T1
T1 x;

804

Metaprogramming

Chapter 28

using Base = Tuple;
Base∗ base() { return static_cast(this); }
const Base∗ base() const { return static_cast(this); }
Tuple(const T1& t1, const T2& t2, const T3& t3) :Base{t2, t3}, x{t1} { }
};

These declarations are rather repetitive and follow the simple pattern of the first Tuple (the 4-tuple)
...
That is why I had to provide those Nil default template arguments
...
Specialization will choose one of the simpler Tuples rather than use Nil
...
g
...
5)
...
For example:
tuple{3
...
14

This opens some interesting optimization possibilities
...
This is called the empty-base optimization and is guaranteed
by the language (§27
...
1)
...
5
...
For example:
template
void print_elements(ostream& os, const Tuple& t)
{
os << t
...
base());
}

Section 28
...
1

A Simple Output Function

805

template
void print_elements(ostream& os, const Tuple& t)
{
os << t
...
base());
}
template
void print_elements(ostream& os, const Tuple& t)
{
os << t
...
base());
}
template
void print_elements(ostream& os, const Tuple& t)
{
os << t
...
6
...
1, 42, 'a'};
cout << x << "\n";
cout << Tuple{1
...
2,3,5} << "\n";
cout << Tuple{1
...
2} << "\n";
cout << Tuple<>{} << "\n";

Unsurprisingly, the output is:

806

Metaprogramming

Chapter 28

{ 1
...
2,3,5,7 }
{ 1
...
2,3 }
{ 1
...
5
...
We would like
to access those elements efficiently and without the possibility of type system violations (i
...
, without using casts)
...
The last alternative is what we will use to implement the most common access strategy:
index the elements
...
Unfortunately, I
am unable to implement an appropriate operator[], so I use a function template get():
Tuple x {1
...
1, 42, a }

auto xx = get<0>(x); // xx is a double

The idea is to index the elements, starting from 0, in such a way that the element selection is done
at compile time and we preserve all type information
...
The job of getNth is to return
a reference to the Nth element, which is assumed to have type X
...
base());
}
};

Section 28
...
2

Element Access

807

template
struct getNth {
template
static Ret& get(T& t)
{
return t
...
The member
functions are static because we don’t really want any objects of class getNth
...

This is quite a bit of scaffolding to index into a Tuple, but at least the resulting code is type-safe
and efficient
...

Why must we write get<2>(x) rather than just x[2]? We could try:
template
constexpr auto operator[](T t,int N)
{
return get(t);
}

Unfortunately, this does not work:
• operator[]() must be a member, but we could handle that by defining it within Tuple
...

• I ‘‘forgot’’ that only lambdas can deduce their result type from their return-statement
(§11
...
4), but that could be handled by adding a −>decltype(get(t))
...


28
...
2
...
For example:

Tuple

elements and can be used on the left-hand side of

Tuple x {1
...
1, 42, 'a'};
get<2>(xx) = 'b';
char cc = get<2>(xx);

// error: xx is const
// error: xx is const (surprise?)

The problem is that get() takes its argument by non-const reference
...

Naturally, we also want to be able to have const Tuples
...
1, 422, 'a'};
char cc = get<2>(xx);
// OK: reading from const
cout << "xx: " << xx << "\n";
get<2>(xx) = 'x';
// error : xx is const

To handle const Tuples, we have to add const versions of get() and getNth’s get()
...
base());
}
template
static const Ret& get(const T& t)
// get the value element N from t’s Base
{
return getNth::get(∗t
...
x; }
template static const Ret& get(const T& t) { return t
...


28
...
3 make_tuple
A class template cannot deduce its template arguments, but a function template can deduce them
from its function arguments
...
5
...
and the other four make_Tuples
...
2,3,'x',1223);
cout << "xxx: " << xxx << "\n";

Other useful functions, such as head() and tail(), are easily implemented
...
6
...


28
...
For example, an errorreporting function may take between zero and ten arguments, a matrix may have between one and
ten dimensions, and a tuple can have zero to ten elements
...
In most cases, we would prefer not to
deal with each case separately
...
Also, I pulled the number ten out of a hat: ideally, there
should be no fixed upper limit on the number of elements
...
For example, default arguments (§12
...
5) can
be used to allow a single function to accept a variable number of arguments, and function overloading (§12
...
Passing a single list of
elements (§11
...
However, to elegantly handle the case of an unknown number of
arguments of unknown (and possibly differing) types, some additional language support is needed
...


28
...
1 A Type-Safe printf()
Consider the archetypical example of a function needing an unknown number of arguments of a
variety of types: printf()
...
3)
...

The first argument to printf() is a C-style string interpreted as a ‘‘format string
...
Format specifiers, such as %g for floatingpoint and %s for zero-terminated arrays of characters, control the interpretation of the additional
arguments
...
14);

810

Metaprogramming

Chapter 28

string name = "target";
printf("The value of %s is %P\n",name,Point{34,200});
printf("The value of %s is %g\n",7);

The first call of printf() works as intended, but the second call has two problems: the format specification %s refers to C-style strings, and printf() will not interpret the std::string argument correctly
...
In the third call of printf(), I provided an int as the argument for %s and I ‘‘forgot’’ to provide an argument for %g
...
The output of that last call (if any) would not be pretty
...
As
is common for compile-time programming, the implementation has two parts:
[1] Handle the case where there is just one argument (the format string)
...

The simplest case is the one with only one argument, the format string:
void printf(const char∗ s)
{
if (s==nullptr) return;
while (∗s) {
if (∗s=='%' && ∗++s!='%') // make sure no more arguments are expected
// %% represents plain % in a format string
throw runtime_error("invalid format: missing arguments");
std::cout << ∗s++;
}
}

That prints out the format string
...
A format specifier is defined to be a % not followed
by another % (%% is printf()’s notation for a % that does not start a type specifier)
...
In that case, ∗++s refers to the terminating zero
...
Here is where a template, and in particular a variadic template, comes into play:
template ...
args)
// function argument list: two or more arguments
{
while (s && ∗s) {
if (∗s=='%' && ∗++s!='%') {
// a format specifier (ignore which one it is)
std::cout << value;
// use first non-format argument
return printf(++s, args
...
6
...
When there are no more non-format arguments, it calls the first (simpler)
printf()
...
e
...

The overloading of << replaces the use of the (possibly erroneous) ‘‘hint’’ in the format specifier
...
A formatting character after a % is not used
...

The Args
...
A parameter pack is a sequence of
(type/value) pairs from which you can ‘‘peel off’’ arguments starting with the first
...
args);

is chosen, with the first argument as s, the second as value, and the rest (if any) bundled into the
parameter pack args for later use
...
) the parameter pack args is expanded
so that the first element of args is selected as value and args is one element shorter than in the previous call
...
For example:
template ...
args)
// function argument list: two or more arguments
{
while (s && ∗s) {
if (∗s=='%') { // a format specifier or %%
switch (∗++s) {
case '%':
// not format specifier
break;
case 's':
if (!Is_C_style_string() && !Is_string())
throw runtime_error("Bad printf() format");
break;
case 'd':
if (!Is_integral()) throw runtime_error("Bad printf() format");
break;
case 'g':
if (!Is_floating_point()) throw runtime_error("Bad printf() format");
break;
}

812

Metaprogramming

Chapter 28

std::cout << value;
return printf(++s, args
...


std::is_integral

and

std::is_floating_point,

but you’d have to craft

28
...
2 Technical Details
If you are familiar with functional programming, you should find the printf() example (§28
...
If not, here are minimal technical examples that
might help
...
Types>
void f(Types
...
0);
f(2, 1
...
notation:
template ...
args);
// variadic template function

The typename
...
The

...
The type of each args function argument is the corresponding Types template argument
...
with the same
meaning as typename
...
) is a separate lexical token, so you can place whitespace
before or after it
...
Think of a parameter pack as a sequence of values for which the compiler has remembered the types
...
14}:

char

int

string

double

'c'

127

"Bob"

3
...
The memory layout is not specified by the C++ standard
...
5)
...
To get to a value, we need to start from

Section 28
...
2

Technical Details

813

the beginning and work our way through to what we want
...
5)
...
If we want to, we can give the appearance
of indexed access using something like get for Tuple (and for std::tuple; §28
...
4), but unfortunately there is no direct language support for that
...

after it
...
Args>
void printf(const char∗ s, T value, Args
...

return printf(++s, args
...

}

Expansion of a parameter pack into its elements is not restricted to function calls
...
Bases>
class X : public Bases
...
b) : Bases(b)
...
says that X has zero or more bases
...
One by
one those values are passed to the corresponding base initializer
...
14
...
3), such as in:
• A template argument list
• A function argument list
• An initializer list
• A base specifier list
• A base or member initializer list
• A sizeof
...
expression is used to obtain the number of elements in a parameter pack
...
Types>
class tuple {
//
...
(Types)==2>
tuple(const pair>&);
};

814

Metaprogramming

Chapter 28

28
...
3 Forwarding
One of the major uses of variadic templates is forwarding from one function to another
...
T>
void call(F&& f, T&&
...
);
}

That is pretty simple and not a hypothetical example
...
3
...
2
...
I use pass-by-rvalue-reference of a deduced template argument type to be able to correctly distinguish between rvalues and lvalues (§23
...
2
...
5
...
The
...
is read as ‘‘accept zero or more &&
arguments, each of the type of the corresponding T
...
in forward(t)
...
’’
I used a template argument for the type of the ‘‘something’’ to be called, so that call() can accept
functions, pointers to functions, function objects, and lambdas
...
6
...
2);
call(g1d,1
...
2,"I can't count");
// error : too many arguments for g1d()
call(g2,1,"world!");
int i = 99;
const char∗ p = "Trying";
call(g2,i,p);

// testing with lvalues

call([](){ cout <<"l1()\n"; });
call([](int i){ cout <<"l0(): " << i << "\n";},17);
call([i](){ cout <<"l1(): " << i << "\n"; });
}

I have to be specific about which specialization of a template function to pass because call() cannot
deduce which one to use from the types of the other arguments
...
6
...
5 has an obvious weakness: it can handle at most four elements
...
2
...
2) and explains the
techniques used to implement it
...
Here are
the key definitions:
template ...
>
: private tuple ...

Note that the type is encoded in the type, not stored as data
*/
typedef tuple ...
vtail)
: m_head(v), inherited(vtail
...
VValues>
tuple(const tuple ...
head()), inherited(other
...
VValues>
tuple& operator=(const tuple ...
head();
tail() = other
...

protected:
Head m_head;
private:
Add_reference head() { return m_head; }
Add_const_reference head() const { return m_head; }
inherited& tail() { return ∗this; }
const inherited& tail() const { return ∗this; }
};

There is no guarantee that std::tuple is implemented as hinted here
...

The ‘‘add reference’’ type functions add a reference to a type if it isn’t a reference already
...
4
...

Curiously, std::tuple does not provide head() and tail() functions, so I made them private
...
If you want to access an
element of a tuple, you must (directly or indirectly) call a function that splits it into a value and
...
Tail>
Head head(tuple ...
2
...
2)
}
template ...
> tail(tuple ...
If the designers of
meant for us to use tail() on a tuple, they would have provided it as a member
...
2);
string h = head(tt
...
tail);
// {{1,2,3,4},1
...
Instead, we can deduce them from argument types,

Section 28
...
4

The Standard-Library tuple

817

for example, using the standard-library make_tuple():
template ...
> make_tuple(Types&&
...
>(t
...
20
...
2
...
2);

The standard-library tuple has many more members than listed in the implementation above (hence
the //
...
For example, get() is provided
for element access (like get() from §28
...
2), so we can write:
auto t = make_tuple("Hello tuple", 43, 3
...
15

So std::get() provides compile-time zero-based subscripting of std::tuples
...
There are constructors and
assignments from the same type (copy and move), from other tuple types (copy and move), and
from pairs (copy and move)
...
(§28
...
2) to
ensure that their target tuples have exactly two elements
...
4) and a swap() (§35
...
2)
...
Worse, writing a << for
std::tuple is amazingly complicated because there is no simple and general way of iterating through
the elements of a standard-library tuple
...
One print() recurses through a list printing elements, and the other stops the recursion when
there is no more elements to print:
template // print element N and following elements
struct print_tuple {
template ...
(T))>::type
print(ostream& os, const tuple ...
T>
typename enable_if ...
>&) const
{
}

// empty tuple

};

The pattern is that of a recursive function with a terminating overload (like

printf()

from §28
...
1)
...

We can now write a << for tuple:
std::ostream& operator << (ostream& os, const tuple<>&)
{
return os << "{}";
}

// the empty tuple

template ...
>& t) // a nonempty tuple
{
os << '{' << std::get<0>(t); // print first element
print_tuple<1>::print(os,t); // print the rest of the elements
return os << '}';
}

We can now print a tuple:
void user()
{
cout << make_tuple() << '\n';
cout << make_tuple("One meatball!") << '\n';
cout << make_tuple(1,1
...
7 SI Units Example
Using constexpr and templates, we can compute just about anything at compile time
...

However, I prefer simpler examples that in my opinion stand a better chance when it comes to
maintenance
...
The compilation overhead is minimal and there is no run-time overhead
...
These MKS units are a subset of the international standard (SI) units used universally in science
...

We want to attach units to our values, so as to avoid meaningless computations
...
5 m/s (meters per second)

if (speed == 20)
//
...


// error : 20 is dimensionless
// error : can’t compare m to m/s

Section 28
...

Quantity acceleration = distance/square(time); // MpS2 means m/(s*s)
cout << "speed==" << speed << " acceleration==" << acceleration << "\n";

Units provide a type system for physical values
...
2
...
2
...
A Quantity is a numeric value with a Unit
...
7
...
A Unit is meant for compile-time use
...
This three-value representation
of a unit is very flexible
...
I doubt we will find much use for Quantity<123,−15,1024>, that is, 123 distances
multiplied, divided by 15 masses multiplied, and then multiplied by 1024 time measurements multiplied – but it is nice to know that the system is general
...

When we multiply two quantities, their units are added
...
2) on Units
...
7
...
We can define Quantitys with a variety of units:
Quantity x {10
...
5 meters
// y is 2 seconds

I made the Quantity constructor explicit to make it less likely to get implicit conversions from
dimensionless entities, such as plain C++ floating-point literals:
Quantity s = 7;

// error: attempt to convert an int to meters/second

Quantity comp(Quantity);
//
...
What do we do to physical measurements? I’m
not going to review a whole physics textbook, but certainly we need addition, subtraction, multiplication, and division
...
val+y
...
val−y
...


Section 28
...
2

Quantitys

821

Multiplication Quantitys require addition of their Units
...
For example:
template
Quantity> operator∗(Quantity x, Quantity y)
{
return Quantity>{x
...
val};
}
template
Quantity> operator/(Quantity x, Quantity y)
{
return Quantity>{x
...
val};
}

Given these arithmetic operations, we can express most computations
...
We could use Quantity> but that gets tedious:
Quantity speed {10};
auto double_speed = Quantity>{2}∗speed;

To eliminate that verbosity, we can either provide an implicit conversion from double to
or add a couple of variants to the arithmetic operations
...
val∗y};
}
template
Quantity operator∗(double x, Quantity y)
{
return Quantity{x∗y
...
3+speed;

// error : can’t add a dimensionless scalar to a speed

It is nice to have the detailed requirement for the code precisely dictated by the application domain
...
7
...
5 m/s (meters per second)

That’s not bad, but it is still verbose compared to code that conventionally simply leaves the units in
the heads of the programmers:
auto distance = 10
...
5 m/s (meters per second)

We needed the
...

The code generated for the two examples should be identical, and we can do better still notationally
...
2
...
5 m/s (meters per second)

if (speed == 20)
//
...

if (speed == 10_m/20_s)

// error : 20 is dimensionless
// error : can’t compare m to m/s
// OK: the units match

I defined ∗ and / for combinations of Quantitys and dimensionless values, so we can scale the units
using multiplication or division
...


// milligram
// milliseconds
// microseconds
// nanoseconds

Obviously, this could really get out of control through overuse of nonstandard suffixes (e
...
, us is
suspect even though it is widely used because u looks a bit like a Greek μ)
...
3) but
thought it simpler to keep the Unit types simple and focused on doing their primary task well
...
7
...


28
...
4 Utility Functions
To finish the job (as defined by the initial example), we need the utility function square(), the equality operator, and the output operator
...
val∗x
...
I could have constructed the
Unit right there in the return value definition, but using the existing type function was easier
...

The == looks more or less like all ==s
...
val==y
...
val!=y
...
At run time, they are represented as doubles
...
val << suffix(U::m,"m") << suffix(U::kg,"kg") << suffix(U::s,"s");
}

Finally, we can write:
auto distance = 10_m;
auto time = 20_s;
auto speed = distance/time;

// 10 meters
// 20 seconds
//
...

if (speed == distance)
//
...


// error : 20 is dimensionless
// error : can’t compare m to m/s
// OK: the units match

Quantity acceleration = distance/square(time); // MpS2 means m/(s*s)
cout << "speed==" << speed << " acceleration==" << acceleration << "\n";

Such code will, given a reasonable compiler, generate exactly the same code as would have been
generated using doubles directly
...
It is an example of how we can add a whole new set of application-specific
types with their own checking rules to a C++ program
...
8 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]

Use metaprogramming to improve type safety; §28
...

Use metaprogramming to improve performance by moving computation to compile time;
§28
...

Avoid using metaprogramming to an extent where it significantly slows down compilation;
§28
...

Think in terms of compile-time evaluation and type functions; §28
...

Use template aliases as the interfaces to type functions returning types; §28
...
1
...
2
...

Use traits to nonintrusively associate properties with types; §28
...
4
...
3
...
1
...
3
...
3
...
3
...

Use metaprogramming for tasks that cannot be done well at run time; §28
...
3
...
4
...
4
...


Section 28
...
6
...
6
...
6
...

[17] Use simple metaprogramming to implement efficient and elegant unit systems (for finegrained type checking); §28
...

[18] Use user-defined literals to simplify the use of units; §28
...


This page intentionally left blank

29
A Matrix Design
Never express yourself more clearly
than you are able to think
...
1 Introduction
A language feature in isolation is boring and useless
...

I have never seen a perfect matrix class
...
Here, I present the programming and design techniques needed
to write a simple N-dimensional dense matrix
...
The design and programming techniques used for Matrix are widely applicable
...
1
...
It can be used like this:

Matrix m0 {1};
// zero dimensions: a scalar
Matrix m1 {1,2,3,4};
// one dimension: a vector (4 elements)
Matrix m2 {
// two dimensions (4*3 elements)
{00,01,02,03},
// row 0
{10,11,12,13},
// row 1
{20,21,22,23}
// row 2
};
Matrix m3(4,7,9);
// three dimensions (4*7*9 elements), all 0-initialized
Matrix,17> m17; // 17 dimensions (no elements so far)

The element type must be something we can store
...
For example:
Matrix md;
Matrix ms;

// OK
// OK: just don’t try arithmetic operations

Matrix,2> mm { // 3-by-2 matrix of 2-by-2 matrices
// a matrix is a plausible "number"
{ // row 0
{{1, 2}, {3, 4}}, // col 0
{{4, 5}, {6, 7}}, // col 1
},
{ // row 1
{{8, 9}, {0, 1}}, // col 0
{{2, 3}, {4, 5}}, // col 1
},
{ // row 2
{{1, 2}, {3, 4}}, // col 0
{{4, 5}, {6, 7}}, // col 1
}
};

Matrix arithmetic doesn’t have exactly the same mathematical properties as integer or floatingpoint arithmetic (e
...
, matrix multiplication is not commutative), so we must be careful how we use
such a matrix
...
3
...
1, §17
...
4
...

The number rows must match the specified number of dimensions and the number of elements in
each dimension (each column) must match
...
1
...

Each dimension has a number of elements (its extent()) deduced from the initializer list or specified
as a Matrix constructor argument using the () notation
...
For example:
Matrix

Matrix m1(100);
Matrix m2(50,6000);

// one dimension: a vector (100 elements)
// two dimensions: 50*6000 elements

auto d1 = m1
...
order();

// 1
// 2

auto e1 = m1
...
extent(1);

// 100
// error : m1 is one-dimensional

auto e2 = m2
...
extent(1);

// 50
// 6000

auto s1 = m1
...
size();

// 100
// 50*6000

We can access Matrix elements by several forms of subscripting
...
3)
...
4), so this operator<<() returns an ostream&
...


830

A Matrix Design

Chapter 29

29
...
2 Matrix Requirements
Before proceeding with an implementation, consider what properties we might like to have:
• N dimensions, where N is a parameter that can vary from 0 to many, without specialized
code for every dimension
...

• The mathematical operations should apply to any type that can reasonably be described as a
number, including a Matrix
...

• C-style subscripting, for example, m[7], yielding a row (a row is an N−1-D sub-Matrix of an
N-D Matrix)
...

• Move assignment and move constructor to ensure efficient passing of Matrix results and to
eliminate expensive temporaries
...

• A way to read, write, and pass around references to submatrices, Matrix_refs, for use for both
reading and writing elements
...
2)
...

This is a relatively long and ambitious list, but it does not add up to ‘‘everything for everybody
...
g
...

To provide this, I use a combination of several language features and programming techniques:
• Classes (of course)
• Parameterization with numbers and types
• Move constructors and assignments (to minimize copying)
• RAII (relying on constructors and destructors)
• Variadic templates (for specifying extents and for indexing)
• Initializer lists
• Operator overloading (to get conventional notation)
• Function objects (to carry information about subscripting)
• Some simple template metaprogramming (e
...
, for checking initializer lists and for distinguishing reading and writing for Matrix_refs)
• Implementation inheritance for minimizing code replication
...
Instead, facilities are provided for users to make their own
...
2

A Matrix Template

29
...
Exts>
explicit Matrix(Exts
...
extents[n]; }
size_t size() const { return elems
...
data(); }
const T∗ data() const { return elems
...

private:
Matrix_slice desc;
vector elems;
};

// slice defining extents in the N dimensions
// the elements

831

832

A Matrix Design

Chapter 29

Using a vector to hold the elements relieves us from concerns of memory management and
exception safety
...
4
...
Think of it as a gslice (§40
...
6) specialized for our Matrix
...
4
...
Think of it as a reference to
a sub-Matrix
...
4
...


29
...
1 Construction and Assignment
The default copy and move operations have just the right semantics: memberwise copy or move of
the desc (slice descriptor defining subscripting) and the elements
...
Similarly, the default constructor and
destructor have just the right semantics
...
6):
template
template ...
exts)
:desc{exts
...
size) // allocate desc
...
extents);
elems
...
size);
Matrix_impl::insert_flat(init,elems);
assert(elems
...
size);
}

// deduce extents from initializer list (§29
...
4)
// make room for slices
// initialize from initializer list (§29
...
4)

The

Matrix_initializer is a suitably nested initializer_list (§29
...
4)
...
Then, the elements are stored in elems by
insert_flat() from the Matrix_impl namespace
...
This is to enforce the use of () initialization for extents
...
2
...

Finally, we have to be able to construct from a Matrix_ref, that is, from a reference to a Matrix or
a part of a Matrix (a submatrix):
template
template
Matrix::Matrix(const Matrix_ref& x)
:desc{x
...
begin(),x
...

As usual, the assignments resemble the constructors
...
desc;
elems
...
begin(),x
...


29
...
2 Subscripting and Slicing
A Matrix can be accessed through subscripting (to elements or rows), through rows and columns, or
through slices (parts of rows or columns)
...
row(i)
m
...
row(i)
Fortran-style element access: m[i][j]; a T&;
the number of subscripts must be N
Submatrix access with slicing: a Matrix_ref;
slice(i,n) is elements [i:i+n) of the subscript’s dimension;
slice(j) is elements [i:max) of the subscript’s dimension;
max is the dimension’s extent; the number of subscripts must be N

These are all member functions:
template
class Matrix {
public:
//
...
Args>
// m(i,j,k) subscripting with integers
Enable_if ...
args);
template ...
>(), const T&>
operator()(Args
...
Args>
// m(s1,s2,s3) subscripting with slices
Enable_if ...
args);
template ...
>(), Matrix_ref>
operator()(const Args&
...

};

C-style subscripting is done by m[i] selecting and returning the ith row:
template
Matrix_ref Matrix::operator[](size_t n)
{
return row(n); // §29
...
5
}

Think of a Matrix_ref (§29
...
3) as a reference to a sub-Matrix
...
4
...

Fortran-style subscripting is done by listing an index for each dimension, for example,
yielding a scalar:

m(i,j,k),

Matrix m2 {
{01,02,03},
{11,12,13}
};
m(1,2) = 99;
// overwrite the element in row 1 column 2; that is 13
auto d1 = m(1);
// error : too few subscripts
auto d2 = m(1,2,3); // error : too many subscripts

In addition to subscripting with integers, we can subscript with slices
...
5
...
In particular, slice{i,n} refers to elements [i:i+n) of the
dimension to which it applies
...
2
...

The return type for a () with slice subscripts is a Matrix_ref, so we can use it as the target of an
assignment
...
So, we can simplify
m(slice{1,2},slice{0,3}) to the equivalent m(slice{1,2},slice{0})
...
For example:
Matrix m3 {
{01,02,03},
{11,12,13},
{21,22,23}
};
auto m31 = m(slice{1,2},1);
auto m32 = m(slice{1,2},0);
auto x = m(1,2);

// m31 becomes {{12},{22}}
// m33 becomes {{11},{21}}
// x == 13

The notion of slicing subscripts is supported in essentially all languages used for numeric programming, so hopefully it is not too unfamiliar
...
4
...
The implementations of const versions of these functions are basically the same as those of their non-const
versions
...


29
...
However, what we often
want is to have mathematical operations that save us from expressing our algorithms in terms of
accesses to individual elements (scalars)
...

template
Matrix& apply(F f);

// f(x) for every element x

template
Matrix& apply(const M& m, F f);

// f(x,mx) for corresponding elements

Matrix& operator=(const T& value);

// assignment with scalar

Matrix& operator+=(const T& value);
Matrix& operator−=(const T& value);
Matrix& operator∗=(const T& value);
Matrix& operator/=(const T& value);
Matrix& operator%=(const T& value);

// scalar addition
// scalar subtraction
// scalar multiplication
// scalar division
// scalar modulo

template
Matrix& operator+=(const M& x);
template
Matrix& operator−=(const M& x);

// matrix addition

//
...
3
...
3
...

For example:
template
Matrix& Matrix::operator+=(const T& val)
{
return apply([&](T& a) { a+=val; } ); // using a lambda (§11
...
For example:
m
...
apply(sqrt);

// m[i] = sqrt(abs(m[i])) for all i

As usual (§3
...
1
...
3), we can define the ‘‘plain operators,’’ such as +, outside the class using
the assignment operators, such as +=
...


29
...
2 Addition
Addition of two Matrixes is very similar to the scalar versions:
template
template
Enable_if(),Matrix&> Matrix::operator+=(const M& m)
{
static_assert(m
...
descriptor()));
// make sure sizes match
return apply(m, [](T& a,Value_type&b) { a+=b; });
}
Matrix::apply(m,f)

(m and ∗this):

is the two-argument version of

Matrix::apply(f)
...
descriptor()));
// make sure sizes match
for (auto i = begin(), j = m
...
We could generalize:
templatetypename RT = Matrix,Value_type>,N>
Matrix operator+(const Matrix& a, const Matrix& b)
{
Matrix res = a;
res+=b;
return res;
}

If, as is common, T and T2 are the same type, Common_type is that type
...
4
...
For built-in types it, like ?:, gives a type that
best preserves values of arithmetic operations
...
For example:
template<>
struct common_type {
using type = Quad;
};

Now Common_type is Quad
...
4
...
For example:
template
Matrix operator+(const Matrix_ref& x, const T& n)
{
Matrix res = x;
res+=n;
return res;
}

Section 29
...
2

Addition

839

Such operations look exactly like their Matrix equivalents
...

Subtraction, multiplication, etc
...


29
...
3 Multiplication
Matrix multiplication is not as simple as addition: the product of an N-by-M matrix and a M-by-P
matrix is an N-by-P matrix
...
We can generalize matrix multiplication into higher dimensions, but to do that we have to introduce tensors [Kolecki,2002], and I
don’t want to divert this discussion of programming techniques and how to use language features
into a physics and engineering math lesson
...

Treating one Matrix as an N-by-1 matrix and another as a 1-by-M matrix, we get:
template
Matrix operator∗(const Matrix& u, const Matrix& v)
{
const size_t n = u
...
extent(0);
Matrix res(n,m);
// an n-by-m matrix
for (size_t i = 0; i!=n; ++i)
for (size_t j = 0; j!=m; ++j)
res(i,j) = u[i]∗v[j];
return res;
}

This is the simplest case: matrix element res(i,j) is u[i]∗v[j]
...
If necessary, the techniques discussed for addition can be used
...
This roughly doubles the cost of the multiplication
...

Next, we can multiply an N-by-M matrix with a vector seen as an M-by-1 matrix
...
extent(1)==v
...
extent(0);
Matrix res(n);
for (size_t i = 0; i!=n; ++i)
for (size_t j = 0; j!=n; ++j)
res(i) += m(i,j)∗v(j);
return res;
}

840

A Matrix Design

Chapter 29

Note that the declaration of res initializes its elements to T{}, which is zero for numeric types, so
that the += starts out from zero
...
extent(0);
const size_t m = m1
...
extent(0));
// columns must match rows
const size_t p = m2
...

That innermost loop could be more elegantly expressed as:
res(i,j) = dot_product(m1[i],m2
...
6
...
begin(),a
...
begin(),0
...
4 Matrix Implementation
So far, I have delayed the presentation of the most complicated (and for some programmers the
most interesting) ‘‘mechanical’’ parts of the Matrix implementation
...
In that case, add
inline the definition of every nonmember function
...


Section 29
...
1

slice()

841

29
...
1 slice()
A simple slice as used for slice subscripting describes a mapping from an integer (subscript) to an
element location (index) in terms of three values:
struct slice {
slice() :start(−1), length(−1), stride(1) { }
explicit slice(size_t s) :start(s), length(−1), stride(1) { }
slice(size_t s, size_t l, size_t n = 1) :start(s), length(l), stride(n) { }
size_t operator()(size_t i) const { return start+i∗stride; }
static slice all;
size_t start;
size_t length;
size_t stride;

// first index
// number of indices included (can be used for range checking)
// distance between elements in sequence

};

There is a standard-library version of slice; see §40
...
4 for a more thorough discussion
...
g
...


29
...
2 Matrix Slices
A Matrix_slice is the part of the Matrix implementation that maps a set of subscripts to the location
of an element
...
5
...
Dims>
Matrix_slice(Dims
...
Dims,
typename = Enable_if()
...
dims) const;
// calculate index from a set of subscripts
size_t size;
size_t start;
array extents;
array strides;

// total number of elements
// star ting offset
// number of elements in each dimension
// offsets between elements in each dimension

};

In other words, a Matrix_slice describes what is considered rows and columns in a region of memory
...
A Matrix_slice is a
function object, and its operator()() does a stride calculation (§40
...
6):

842

A Matrix Design

Chapter 29

template
template ...
dims) const
{
static_assert(sizeof
...
};

// Copy arguments into an array

return inner_product(args,args+N,strides
...
This is a simplified algorithm that needs to be optimized
...
For example:
template<>
struct Matrix_slice<1> {
//
...

size_t operator()(size_t i, size_t j) const
{
return i∗stides[0]+j;
}
}

The Matrix_slice is fundamental for defining the shape of a Matrix (its extents) and for implementing
N-dimensional subscripting
...


29
...
3 Matrix_ref
A

is basically a clone of the Matrix class used to represent sub-Matrixes
...
It is constructed from a Matrix_slice and a pointer to elements:

Matrix_ref

Matrix_ref

template
class Matrix_ref {
public:
Matrix_ref(const Matrix_slice& s, T∗ p) :desc{s}, ptr{p} {}
//
...


Section 29
...
3

Matrix_ref

private:
Matrix_slice desc;
T∗ ptr;
};

843

// the shape of the matrix
// the first element in the matrix

A Matrix_ref simply points to the elements of ‘‘its’’
live its Matrix
...


Obviously, a

Matrix_ref

should not out-

Matrix_ref user()
{
Matrix m = {{1,2}, {3,4}, {5,6}};
return m
...
If that becomes a bother,
we can derive both from a common base:
template
class Matrix_base {
//
...

};
template
class Matrix : public Matrix_base {
//
...

private:
Matrix_slice desc; // the shape of the matrix
vector elements;
};
template
class Matrix_ref : public Matrix_base {
//
...

private:
Matrix_slice desc; // the shape of the matrix
T∗ ptr;
};

29
...
4 Matrix List Initialization
The

Matrix constructor
Matrix_initializer:

that constructs from an

initializer_list

takes as its argument type the alias

template
using Matrix_initializer = typename Matrix_impl::Matrix_init::type;
Matrix_init

describes the structure of a nested initializer_list
...
That is where we get to the (most deeply nested) initializer_list:
template
struct Matrix_init {
using type = initializer_list;
};

To avoid surprises, we define N=0 to be an error:
template
struct Matrix_init;

// undefined on purpose

We can now complete the Matrix constructor that takes a Matrix_initializer:
template
Matrix::Matrix(Matrix_initializer init)
{
Matrix_impl::derive_extents(init,desc
...
reserve(desc
...
size() == desc
...
4
...
4
...

The derived_extents() called from a Matrix constructor to initialize its desc looks like this:
template
array derive_extents(const List& list)
{
array a;
auto f = a
...

The recursion is done from N to the final 1 where the initializer_list is an initializer_list
...
4
...
size();
add_extents(++first,∗list
...
size();
// we reached the deepest nesting
}

The check_non_jagged() function checks that all rows have the same number of elements:
template
bool check_non_jagged(const List& list)
{
auto i = list
...
end(); ++j)
if (i−>size()!=j−>size())
return false;
return true;
}

We need insert_flat() to take a possibly nested initializer list and present its elements to Matrix as
a vector
...
begin(),list
...
If we have a list of initializer_lists, we recurse
through each:
template // nested initializer_lists
void add_list(const initializer_list∗ first, const initializer_list∗ last, Vec& vec)
{
for (;first!=last;++first)
add_list(first−>begin(),first−>end(),vec);
}

When we reach a list with non-initializer_list elements, we insert those elements into our vector:

846

A Matrix Design

Chapter 29

template
void add_list(const T∗ first, const T∗ last, Vec& vec)
{
vec
...
end(),first,last);
}

I use vec
...
end(),first,last) because there is no push_back() that takes a sequence argument
...
4
...
4
...
4
...
A row() or column() operation returns a Matrix_ref, the () subscript operation with integers returns a T&, and
the () subscript operation with slices returns a Matrix
...


The difference is simply in the

template
Matrix_ref Matrix::column(size_t n)
{
assert(nMatrix_slice col;
Matrix_impl::slice_dim<1>(n,desc,col);
return {col,data()};
}

The const versions are equivalent
...
4
...
They check that a
sequence of access-function arguments are of suitable types for use as subscripts
...
4
...
Args>
Enable_if ...
args)
{
assert(Matrix_impl::check_bounds(desc, args
...
));
}

The check_bounds() predicate checks that the number of subscripts equals the number of dimensions and that the subscripts are within bounds:
template ...
dims)
{
size_t indexes[N] {size_t(dims)
...
extents, less {});
}

The actual location of the element in the Matrix is calculated by invoking the Matrix’s Matrix_slice’s
generalized slice calculation presented as a function object: desc(args
...
));

This leaves the most mysterious part of the declaration for last
...
>(),T&>

So the return type is T& provided that
Matrix_impl::Requesting_element ...
4)
...
4
...
Args>
constexpr bool Requesting_element()
{
return All(Convertible()
...
Args>
constexpr bool All(bool b, Args
...
);
}

required

848

A Matrix Design

Chapter 29

The reason for using a predicate (Requesting_element) and the Enable_if() ‘‘hidden’’ within Request
is to choose between the element and the slice subscript operators
...
Args>
constexpr bool Requesting_slice()
{
return All((Convertible() || Same())
...
);
}

That is, if there is at least one slice argument and if all arguments are either convertible to
size_t, we have something that can be used to describe a Matrix:

slice

or

template
// subscripting with slices
template ...
>(), Matrix_ref>
Matrix::operator()(const Args&
...
start = matrix_impl::do_slice(desc,d,args
...
Args>
size_t do_slice(const Matrix_slice& os, Matrix_slice& ns, const T& s, const Args&
...
(Args)+1>(os,ns,s);
size_t n = do_slice(os,ns,args
...


29
...
6 Zero-Dimensional Matrix
The

Matrix code contains a lot of occurrences of N−1 where N is the number of dimensions
...
Here, we solve the problem by defining a specialization:

Section 29
...
6

Zero-Dimensional Matrix

849

template
class Matrix {
public:
static constexpr size_t order = 0;
using value_type = T;
Matrix(const T& x) : elem(x) { }
Matrix& operator=(const T& value) { elem = value; return ∗this; }
T& operator()() { return elem; }
const T& operator()() const { return elem; }
operator T&() { return elem; }
operator const T&() { return elem; }
private:
T elem;
};

is not really a matrix
...


Matrix

29
...
The
example used here should be rather trivial if you have learned basic linear algebra; if not, just see it
as an example of transcribing a textbook solution into code with minimal rewording
...

We will solve a set (any set) of linear equations of this form:
a1,1 x 1 +
...


...
For simplicity, we assume
that the unknowns and the constants are floating-point values
...
These equations can compactly be expressed
in terms of a matrix and two vectors:
Ax =b

Here, A is the square n-by-n matrix defined by the coefficients:
⎡ a1,1
A = ⎢
...


...


a1,n ⎤

...
⎥ , and b = ⎢
...
There are various methods for solving linear systems
...
First,
we transform A and b so that A is an upper-triangular matrix
...
In other words, the system looks like this:
⎡ a1,1
⎢ 0

⎣ 0


...

0

a1,n ⎤ ⎡ x 1 ⎤ ⎡ b1 ⎤

...
A zero for position a(i,j) is obtained by multiplying the equation for row i by a
constant so that a(i,j) equals another element in column j, say a(k,j)
...

If we can get all the diagonal coefficients to be nonzero, then the system has a unique solution,
which can be found by ‘‘back substitution
...
That done, eliminate row n from the system and proceed to find the
value of x[n−1], and so on, until the value for x[1] is computed
...
If that does not hold, the back substitution method fails, meaning
that the system has zero or an infinite number of solutions
...
5
...
First, we’ll simplify our notation by conventionally naming the two Matrix types that we are going to use:
using Mat2d = Matrix;
using Vec = Matrix;

Next, we will express our desired computation:
Vec classical_gaussian_elimination(Mat2d A, Vec b)
{
classical_elimination(A, b);
return back_substitution(A, b);
}

That is, we make copies of our inputs A and b (using call-by-value), call a function to solve the system, and then calculate the result to return by back substitution
...
To complete our solution, we have to implement classical_elimination() and back_substitution()
...
5
...
dim1();
// traverse from 1st column to the next-to-last, filling zeros into all elements under the diagonal:
for (size_t j = 0; j!=n−1; ++j) {
const double pivot = A(j, j);
if (pivot==0) throw Elim_failure(j);
// fill zeros into each element under the diagonal of the ith row:
for (size_t i = j+1; i!=n; ++i) {
const double mult = A(i,j) / pivot;
A[i](slice(j)) = scale_and_add(A[j](slice(j)), −mult,A[i](slice(j)));
b(i) −= mult∗b(j); // make the corresponding change to b
}
}
}

The pivot is the element that lies on the diagonal of the row we are currently dealing with
...
dim1();
Vec x(n);
for (size_t i = n−1; i>=0; −−i) {
double s = b(i)−dot_product(A[i](slice(i+1)),x(slice(i+1)));
if (double m = A(i,i))
x(i) = s/m;
else
throw Back_subst_failure(i);
}
return x;
}

29
...
2 Pivoting
We can avoid the divide-by-zero problem and also achieve a more robust solution by sorting the
rows to get zeros and small values away from the diagonal
...
However, the values change as we go along placing zeros under the diagonal, so we have to also reorder to get small values away from the diagonal (that is, we can’t just
reorder the matrix and then use the classical algorithm):
void elim_with_partial_pivot(Mat2d& A, Vec& b)
{
const size_t n = A
...
swap_rows(j,pivot_row);
std::swap(b(j),b(pivot_row));
}
// elimination:
for (size_t i = j+1; i!=n; ++i) {
const double pivot = A(j,j);
if (pivot==0) error("can't solve: pivot==0");
const double mult = A(i,j)/pivot;
A[i]
...
slice(j), −mult, A[i]
...


29
...
3 Testing
Obviously, we have to test our code
...
what() << endl;
}
}

We can get to the catch-clause in three ways:

Section 29
...
3

Testing

853




A bug in the code (but, being optimists, we don’t think there are any)
An input that trips up classical_elimination() (using elim_with_partial_pivot() would minimize
the chances of that)
• Rounding errors
However, our test is not as realistic as we’d like because genuinely random matrices are unlikely to
cause problems for classical_elimination()
...
The likelihood of rounding errors is the reason we didn’t just do:
if (A∗x!=b) error("substitution failed");

Because floating-point numbers are just approximations to real numbers, we have to accept approximately correct answers
...
Had I felt the need for a machine
check, I would have defined an equal() function with a notion of which error ranges to consider
acceptable and then written:
if (equal(A∗x,b)) error("substitution failed");

The random_matrix() and random_vector() are simple uses of random numbers and are left as simple
exercises for the reader
...
5
...

[2] Copying of matrices must be minimized
...

Consider U=M∗V+W, where U, V, and W are vectors (Matrix) and M is a Matrix
...
A smart implementation calls a function mul_add_and_assign(&U,&M,&V,&W) that introduces no temporaries, copies no vectors, and touches each element of the matrices the minimum
number of times
...
If we had written
Matrix U=M∗V+W;

we would have eliminated all element copies: the elements allocated in the local variable in M∗V are
the ones ending up in U
...
This degree of optimization is rarely
necessary for more than a few kinds of expressions, so a simple solution to efficiency problems is
to provide functions such as mul_add_and_assign() and let the user call those where it matters
...
That is, we can treat U=M∗V+W as a use of a single operator with four
operands
...
4
...
2)
...
Handling
U=M∗V+W requires the introduction of two auxiliary classes
...
First, for simplicity, let us restrict ourselves to two-dimensional matrices of doubleprecision floating-point numbers:
using Mat2d = Matrix;
using Vec = Matrix;

We define the result of multiplying a Mat2d by a Vec:
struct MVmul {
const Mat2d& m;
const Vec& v;
MVmul(const Mat2d& mm, const Vec &vv) :m{mm}, v{vv} { }
operator Vec(); // evaluate and return result
};
inline MVmul operator∗(const Mat2d& mm, const Vec& vv)
{
return MVmul(mm,vv);
}

This ‘‘multiplication’’ should replace the one from §29
...
The object produced by ∗ is closely related to
what is called a closure in many technical communities
...
m), v(mv
...
We now have to ensure that it all gets evaluated using a good
algorithm when it is assigned to a Vec:
template<>
class Matrix {
//
...
5
...

mul_add_and_assign(this,&m
...
v,&m
...
m,&m
...
v2);
return ∗this;
}
//
...
operator=(MVmulVadd(MVmul(M,V),W))

which because of inlining resolves to the desired simple call
mul_add_and_assign(&U,&M,&V,&W)

Clearly, this eliminates the copying and the temporaries
...
However, if we just wrote it in a fairly simple and
unoptimized fashion, it would still be in a form that offered great opportunities to an optimizer
...
Typically, there is no real gain in optimizing expressions of half a dozen operators
...

This technique is based on the idea of using compile-time analysis and closure objects to transfer evaluation of a subexpression into an object representing a composite operation
...
I refer to the objects generated to
defer evaluation as composition closure objects, or simply compositors
...
Expression templates systematically
use function objects to represent expressions as abstract syntax trees (ASTs)
...
6 Advice
[1]
[2]
[3]
[4]

List basic use cases; §29
...
1
...
g
...
1
...

Carefully list the properties a program, class, or library ideally should have; §29
...
2
...
1
...


856

[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]
[14]
[15]
[16]
[17]

A Matrix Design

Chapter 29

When designing a container template, carefully consider the requirements on the element
type; §29
...
2
...
g
...
1
...

If possible, design a class to mimic existing professional notation and semantics; §29
...
2
...
g
...
2
...
1
...

Provide complete, flexible, efficient, and semantically meaningful access to elements;
§29
...
2, §29
...

Place implementation details in their own _impl namespace; §29
...

Provide common operations that do not require direct access to the representation as helper
functions; §29
...
2, §29
...
3
...
4
...
4
...
4
...

The structure of data can often be expressed as nested initializer lists; §29
...
4
...
4
...

In addition to unit testing and testing that the code meets its requirements, test the design
through examples of real use; §29
...

Consider how the design might accommodate unusually stringent performance requirements;
§29
...
4

Part IV
The Standard Library
This part describes the C++ standard library
...


Chapters
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

Standard-Library Overview
STL Containers
STL Algorithms
STL Iterators
Memory and Resources
Utilities
Strings
Regular Expressions
I/O Streams
Locales
Numerics
Concurrency
Threads and Tasks
The C Standard Library
Compatibility

858

The Standard Library

Part IV

‘‘
...
As long as it consists solely of description it is pretty easy; but where reasoning
comes into play, to make a proper connection, a clearness & a moderate fluency, is to
me, as I have said, a difficulty of which I had no idea
...

– Roger Bacon







Introduction
Standard-Library Facilities; Design Constraints; Description Style
Headers
Language Support
initializer_list Support; Range-for Support
Error Handling
Exceptions; Assertions; system_error
Advice

30
...
For portability and longterm maintainability, I strongly recommend using the standard library whenever feasible
...
’’ In general: try not to reinvent the wheel
...
And that is without describing the ISO C standard library, which is a part of the C++ standard library (another 139 pages)
...
Here,
I summarize, relying heavily on tables, and give a few examples
...
Rely on the references to the standard for
complete details
...
Each
chapter and typically each major subsection can be read in isolation
...


30
...
1 Standard-Library Facilities
What ought to be in the standard C++ library? One ideal is for a programmer to be able to find
every interesting, significant, and reasonably general class, function, template, etc
...

However, the question here is not ‘‘What ought to be in some library?’’ but ‘‘What ought to be in
the standard library?’’ ‘‘Everything!’’ is a reasonable first approximation to an answer to the former question but not to the latter
...

The C++ standard library provides:
• Support for language features, such as memory management (§11
...
5
...
2)
• Information about implementation-defined aspects of the language, such as the largest finite
float value (§40
...
4
...
3)
• Support for thread-based concurrency (§5
...
2)
• Minimal support for task-based concurrency, such as future and async() (§42
...
5) and memmove() (§43
...
5)
• Nonprimitive foundational facilities that a programmer can rely on for portability, such as
lists (§31
...
4
...
6), and I/O streams (Chapter 38)
• Frameworks for extending the facilities it provides, such as conventions and support facilities that allow a user to provide I/O of a user-defined type in the style of I/O for built-in
types (Chapter 38) and the STL (Chapter 31)
A few facilities are provided by the standard library simply because it is conventional and useful to
do so
...
3), random number
generators (§40
...
4), and regular expressions (Chapter 37)
...
In particular, combinations of its facilities allow the standard library to play three supporting roles:

Section 30
...
1

Standard-Library Facilities

861




A foundation for portability
A set of compact and efficient components that can be used as the foundation for performance-sensitive libraries and applications
• A set of components enabling intra-library communications
The design of the library is primarily determined by these three roles
...
For example, portability is commonly an important design criterion for a specialized
library, and common container types such as lists and maps are essential for convenient communication between separately developed libraries
...
For example, string and list facilities
are provided in the standard library
...
However, advanced linear algebra and graphics facilities are not
provided
...

Unless a facility is somehow needed to support these roles, it can be left to some library outside
the standard
...
Once a library proves itself
widely useful in a variety of computing environments and application domains, it becomes a candidate for the standard library
...

A reduced standard library is available for freestanding implementations, that is, implementations running with minimal or no operating system support (§6
...
1)
...
1
...
The facilities offered by
the C++ standard library are designed to be:
• Valuable and affordable to essentially every student and professional programmer, including
the builders of other libraries
...

• Efficient enough to provide genuine alternatives to hand-coded functions, classes, and templates in the implementation of further libraries
...

• Primitive in the mathematical sense
...

• Convenient, efficient, and reasonably safe for common uses
...
The standard library may leave major functions to other
libraries, but if it takes on a task, it must provide enough functionality so that individual
users or implementers need not replace it to get the basic job done
...

• Type safe by default, and therefore in principle checkable at run time
...

• Extensible to deal with user-defined types in ways similar to the way built-in types and standard-library types are handled
...
This is why the C standard-library qsort() takes a
comparison function as an argument rather than relying on something fixed, say, the < operator
(§12
...
On the other hand, the overhead imposed by a function call for each comparison compromises qsort() as a building block for further library building
...

Is that overhead serious? In most cases, probably not
...
The technique described in §25
...
3 of supplying comparison criteria through a template argument solves
that problem for sort() and many other standard-library algorithms
...
It is also an example of how such tensions can be
resolved
...
It must also perform them
so efficiently that users are not tempted to supply their own alternatives to what the standard offers
...
This would add a burden to the library developer and seriously complicate the lives of users wanting to stay platform-independent or to use several separately developed libraries
...
The
former requirement precludes exclusively optimizing the standard library for common cases
...
The cult of orthogonality must
not prevent us from making life convenient for the novice and the casual user
...


30
...
3 Description Style
A full description of even a simple standard-library operation, such as a constructor or an algorithm, can take pages
...
Sets of
related operations are typically presented in tables:
Some Operations
p=op(b,e,x)
foo(x)
bar(b,e,x)

op does something to the range [b:e) and x, returning p
foo does something to x but returns no result
Does x have something to do with [b:e)?

I try to be mnemonic when choosing identifiers, so b and e will be iterators specifying a range, p a
pointer or an iterator, and x some value, all depending on context
...
For an operation returning a Boolean, the explanation usually ends with a question mark
...
(§4
...
1, §33
...
1), I do not mention that explicitly
...


Section 30
...
2 Headers
The facilities of the standard library are defined in the std namespace and presented as a set of
headers
...
Thus, listing them gives an overview
of the library
...
The grouping is chosen to match
the organization of the standard
...
For every header ...
Ideally, the names from
a header do not pollute the global namespace (§15
...
4), but unfortunately (due to complexities
of maintaining multilanguage, multi-operating-system environments) most do
...
5
...


§31
...
2
§31
...
2
§31
...
2
§31
...
2
§31
...
3
§31
...
3
§31
...
3
...
4
...
2
§31
...
2
§31
...
1
§34
...
1
§34
...
2



and

,

respectively
...
5, §34
...
4
...
2
...
2
§35
...
1
§35
...
4
§33
...
3
§34
...
4
§35
...
2
§43
...
1

Iterators provide the mechanism to make standard algorithms generic (§3
...
2, §33
...
4)
...
2
§43
...
4
...
2) of any type of element
...
5)
...
4
...
1
§30
...
1
...
4
...
1
...
4
...
4
...
2
...
2
...
4
§36
...
1
§43
...
, family of functions
...

Input/Output













Forward declarations of I/O facilities
Standard iostream objects and operations
iostream bases
Stream buffers
Input stream template
Output stream template
Manipulators
Streams to/from strings
Character classification functions
Streams to/from files
printf() family of I/O
printf()-style I/O of wide characters

§38
...
1
§38
...
4
§38
...
4
...
4
...
4
...
2
§38
...
2
§36
...
1
§38
...
1
§43
...
3

Manipulators are objects used to manipulate the state of a stream (§38
...
5
...


Section 30
...
4
...

Language Support















Numeric limits
C-style numeric scalar-limit macros
C-style numeric floating-point limit macros
Standard integer type names
Dynamic memory management
Run-time type identification support
Exception-handling support
initializer_list

C library language support
Variable-length function argument lists
C-style stack unwinding
Program termination
System clock
C-style signal handling

§40
...
2
§40
...
7
§11
...
3
§22
...
4
...
1
§30
...
1
§10
...
1
§12
...
4
§15
...
3
§43
...
3
...
2
...

C-style stack unwinding (using setjmp and longjmp from ) is incompatible with the
use of destructors and with exception handling (Chapter 13, §30
...
C-style
stack unwinding and signals are not discussed in this book
...
3)
...
4
§40
...
6
§40
...
7
§40
...
3
§42
...
4
§42
...
4
§42
...
1
§42
...
The C++ standard
library provides access to all such facilities:
C Compatibility







Aliases for common integer types
C bool

§43
...
The header will not
define a macro alignas
...
h equivalents to , , , and
approximate C++ facilities for C
...

The header provides types (such as fenv_t and fexcept_t), floating-point status flags, and
control modes describing an implementation’s floating-point environment
...
Nor is it acceptable to try to change the contents of a header by defining macros to change
the meaning of declarations in a header (§15
...
3)
...

Even if they work today, the next release of any part of an implementation may break them
...

For a standard-library facility to be used, its header must be included
...
The reason is that some implementations optimize compilation based on standard header inclusion, and others provide optimized
implementations of standard-library facilities triggered by the headers
...

A programmer can, however, specialize utility templates, such as swap() (§35
...
2), for non-standard-library, user-defined types
...
3 Language Support
A small but essential part of the standard library is language support, that is, facilities that must be
present for a program to run because language features depend on them
...
3

Language Support

867

Library Supported Language Features





new and delete
typeid() and type_info
Range-for
initializer_list

§11
...
5
§30
...
2
§30
...
1

30
...
1 initializer_list Support
A {}-list is converted into an object of type std::initializer_list according to the rules described in
§11
...
In , we find initializer_list:
template
class initializer_list {
// §iso
...
9
public:
using value_type = T;
using reference = const T&;
// note const: initializer_list elements are immutable
using const_reference = const T&;
using size_type = size_t;
using iterator = const T∗;
using const_iterator = const T∗;
initializer_list() noexcept;
size_t size() const noexcept;
// number of elements
const T∗ begin() const noexcept; // first element
const T∗ end() const noexcept;
// one-past-last element
};
template
const T∗ begin(initializer_list lst) noexcept { return lst
...
end(); }

Unfortunately, initializer_list does not offer a subscript operator
...
size(); ++i)
cout << lst[i] << '\n';
const int∗ p = lst
...
size(); ++i)
cout << p[i] << '\n';

// error

// OK

}

Naturally, an initializer_list can also be used by a range-for
...
3
...
5
...

In , the standard library provides std::begin() and std::end() functions for built-in arrays
and for every type that provides member begin() and end(); see §33
...

All standard-library containers (e
...
, vector and unordered_map) and strings support iteration
using range-for; container adaptors (such as stack and priority_queue) do not
...


30
...
Thus, their
style and approaches to error handling are not consistent:
• C-style libraries consist of functions, many of which set errno to indicate that an error happened; see §13
...
2 and §40
...

• Many algorithms operating on a sequence of elements return an iterator to the one-past-thelast element to indicate ‘‘not found’’ or ‘‘failure’’; see §33
...
1
...
3
...

The standard library is designed so that all facilities obey ‘‘the basic guarantee’’ (§13
...


30
...
1 Exceptions
Some standard-library facilities report errors by throwing exceptions:
Standard-Library Exceptions (continues)
bitset
iostream
regex
string
vector

Throws invalid_argument, out_of_range, overflow_error
Throws ios_base::failure if exceptions are enabled
Throws regex_error
Throws length_error, out_of_range
Throws out_of_range

Section 30
...
1

Exceptions

869

Standard-Library Exceptions (continued)
new T
dynamic_cast(r)
typeid()
thread
call_once()
mutex
condition_variable
async()
packaged_task
future and promise

Throws bad_alloc if it cannot allocate memory for a T
Throws bad_cast if it cannot convert the reference r to a T
Throws bad_typeid if it cannot deliver a type_info
Throws system_error
Throws system_error
Throws system_error
Throws system_error
Throws system_error
Throws system_error
Throws future_error

These exceptions may be encountered in any code that directly or indirectly uses these facilities
...
For example, a packaged_task will
throw an exception if the function it is required to execute throws
...
) somewhere (§13
...
2
...


30
...
1
...
Instead, throw objects of types specifically defined to be used as exceptions
...
Logic errors are errors that in principle could be caught either before the program
starts executing or by tests of arguments to functions and constructors
...
The system_error is described in §30
...
3
...


870

Standard-Library Overview

Chapter 30

The standard-library exception hierarchy is rooted in class exception:
class exception {
public:
exception();
exception(const exception&);
exception& operator=(const exception&);
virtual ˜exception();
virtual const char∗ what() const;
};

The what() function can be used to obtain a string that is supposed to indicate something about the
error that caused the exception
...
However, all exceptions
thrown by the standard library are from the exception hierarchy
...
For example:
int main()
try {
//
...
interesting_value and me
...
what()
}
catch (exception& e) {
// some standard-librar y exception happened
// we can use e
...
) {
// Some unmentioned exception happened
// we can do local cleanup
}

As for function arguments, we use references to avoid slicing (§17
...
1
...


30
...
1
...
4
...
2

Exception Propagation

871

Exception Propagation (§iso
...
8
...
1
...

Think of exception_ptr as a smart pointer (like shared_ptr) that keeps its exception alive for as long
as an exception_ptr points to it
...
In particular, an exception_ptr can be used to implement a re-throw of an exception in a different thread from the one in which the exception was
caught
...
4) rely on
...

The make_exception_ptr() could be implemented as:
template
exception_ptr make_exception_ptr(E e) noexcept;
try {
throw e;
}
catch(
...
˜nested_exception()
ne
...
nested_ptr()
throw_with_nested(e)
rethrow_if_nested(e)

(§iso
...
8
...
rethrow_nested();
e’s type must be derived from nested_exception

872

Standard-Library Overview

Chapter 30

The intended use of nested_exception is as a base class for a class used by an exception handler to
pass some information about the local context of an error together with a exception_ptr to the
exception that caused it to be called
...

};
void my_code()
{
try {
//
...
) {
My_error err {"something went wrong in my_code()"};
//
...


(rethrown) together with a

nested_exception

holding an

Further up the call chain, we might want to look at the nested exception:
void user()
{
try {
my_code();
}
catch(My_error& err) {
//
...

try {
rethrow_if_nested(err); // re-throw the nested exception, if any
}
catch (Some_error& err2) {
//
...

}
}
}

This assumes that we know that some_error might be nested with My_error
...
5
...
1)
...
4
...
3 terminate()
In , the standard library provides facilities for dealing with unexpected exceptions:

Section 30
...
1
...
18
...
3, §iso
...
8
...
A call of terminate() terminates a program by calling a terminate handler set by a call of set_terminate()
...
For fundamental operating system reasons, it is implementation-defined whether destructors for local objects are invoked
when terminate() is called
...
15
...
1)
...
However, uncaught_exception() is also true during stack unwinding (§13
...
1) after the initial exception
has been caught
...


30
...
2 Assertions
The standard provides:
Assertions (§iso
...

}
}

The assert() is a macro found in
...

Asserts are (as they should be) used more frequently in production code than in small illustrative textbook examples
...
It can be a serious
mistake to assume that the assert() is evaluated when it is not
...

For a way to manage assertions, see §13
...


30
...
3 system_error
In , the standard library provides a framework for reporting errors from the operating
system and lower-level system components
...
first)};
if (err) { // err!=0 means error

// split into {path,name}
// ask "the system" about the path

//
...

if (cannot_handle_err)
throw system_error(err);
}
//
...
4
...
1)
A base class for types used to identify the source and encoding
of a particular kind (category) of error code (§30
...
3
...
4
...
3)
Holds a value identifying an error and the category of that error;
potentially portable (§30
...
3
...
3);
basically POSIX error codes
enum class with enumerators for error codes from (§42
...
4)
enum class with enumerators for error codes from (§38
...
4)

Section 30
...
3
...
4
...
1 Error Codes
When an error ‘‘bubbles up’’ from a lower level as an error code, we must handle the error it represents or turn it into an exception
...

error_code
error_code ec {};
error_code ec {n,cat};
error_code ec {n};

ec
...
clear()
n=ec
...
category()
s=ec
...
19
...
2)

Default constructor: ec={0,&generic_category}; noexcept
ec={n,cat}; cat is an error_category
and n is an int representing an error in cat; noexcept
ec={n,&generic_category};
n represents an error; n is a value of type EE for which
is_error_code_enum::value==true; noexcept
ec={n,cat}; cat is an error_category;
n represents an error; n is a value of type EE for which
is_error_code_enum::value==true; noexcept
ec={n,&generic_category}: ec=make_error_code(n);
n represets an error; n is a value of type EE for which
is_error_code_enum::value==true; noexcept
ec={0,&generic_category()}; noexcept
n is ec’s stored value; noexcept
cat is a reference to ec’s stored category; noexcept
s is a string representing ec potentially used as

an error message: ec
...
message(ec
...
equivalent()
...
default_error_condition()

!(ec==ec2)
An order ec
...
category()
|| (ec
...
category() && ec
...
value())
e is a reference to an error_condition:

os<
e=ec
...
default_error_condition(ec
...
name() to the ostream os

ec=make_error_code(e)

e is an errc;
ec=error_code(static_cast(e),&generic_category())

For a type representing the simple idea of an error code, error_code provides a lot of members
...
Therefore, an
error_category is passed by reference and stored as a pointer
...

Consider again the open_file() example:
ostream& open_file(const string& path)
{
auto dn = split_into_directory_and_name(path);

// split into {path,name}

if (error_code err {does_directory_exist(dn
...

}
else if (err==errc::not_a_directory) {
//
...

return ofstream{path};
}

The errc error codes are described in §30
...
3
...
Note that I used an if-then-else chain rather than
the more obvious switch-statement
...

The operations on error_codes are system-specific
...
4
...
4) using the mechanisms described in §30
...
3
...
An error_condition
is extracted from an error_code using default_error_condition()
...

Manipulating error_codes does not change the value of errno (§13
...
2, §40
...
The standard
library leaves the error states provided by other libraries unchanged
...
4
...
2 Error Categories
An error_category represents a classification of errors
...
interface to specific categories derived from error_category
...
4
...
2

Error Categories

error_category
cat
...
name()

877

(§iso
...
5
...
1)

Destructor; virtual; noexcept
is the name of cat; s is a C-style string;
virtual; noexcept
ec is the error_condition for n in cat; virtual; noexcept
Is ec
...
value()==n?
ec is an error_condition; virtual; noexcept
Is ec
...
value()==n?
ec is an error_code; virtual; noexcept
s is a string describing the error n in cat; virtual
Is cat the same category as cat2? noexcept
!(cat==cat2); noexcept
Is cataddresses: std::less()(cat, cat2)?
noexcept
s

ec=cat
...
equivalent(n,ec)
cat
...
message(n)
cat==cat2
cat!=cat2
cat
Because error_category is designed to be used as a base class, no copy or move operations are provided
...

There are four named standard-library categories:
Standard-library Error Categories (§iso
...
5
...
1)
ec=generic_category()
ec=system_category()

ec=future_category()
iostream_category()

ec
...
name()=="system" ec is a reference to an error_category;
represents system errors: if ec corresponds to a POSIX
error then ec
...
name()=="future"; ec is a reference to an error_category;
represents errors from
ec
...
For example, 1 means ‘‘operation not permitted’’ (EPERM) in
POSIX, is a generic code (state) for all errors as an iostream error, and means ‘‘future already
retrieved’’ (future_already_retrieved) as a future error
...
4
...
3 Exception system_error
A system_error is used to report errors that ultimately originate in the parts of the standard library
that deal with the operating system
...

};

878

Standard-Library Overview

Chapter 30

Exception Class system_error (§iso
...
5
...
code()
p=se
...
For example:
try {
// something
}
catch (system_error& err) {
cout << "caught system_error " << err
...
code();
cout << "category: " << ec
...
what() <<'\n';
cout << "value: " << ec
...
message() <<'\n';
}

Naturally, system_errors can be used by code that is not part of the standard library
...
4
...
4)
...
4
...
1)
...
4
...
4 Potentially Portable Error Conditions
Potentially portable error codes (error_conditions) are represented almost identically to the systemspecific error_codes:
class error_condition { // potentially portable (§iso
...
5
...


Section 30
...
3
...
4
...
5 Mapping Error Codes
Making an error_category with a set of error_codes and at least one error_condition starts with defining an enumeration with the desired error_code values
...
The integer values of these enumerators are implementation-defined
...
The
details are likely to differ from what I describe
...
We have to invent a set
of messages that are likely to be meaningful to a programmer
...
For example, an argument intended to
become the value() of an error_code of future_category() must be a future_errc
...
For example:
error_code ec1 {7};
error_code ec2 {future_errc::no_state};

// error
// OK

ec1 = 9;
ec2 = future_errc::promise_already_satisfied;
ec2 = errc::broken_pipe;

// error
// OK
// error : wrong error category

To help the implementer of error_code, we specialize the trait is_error_code_enum for our enumeration:
template<>
struct is_error_code_enum : public true_type { };

The standard already provides the general template:
template
struct is_error_code_enum : public false_type { };

This states that anything we don’t deem an error code value isn’t
...
For example:

error_condition

to work for

error_condition make_error_condition(future_errc e) noexcept;
template<>
struct is_error_condition_enum : public true_type { };

For a more interesting design, we could use a separate enum for the
make_error_condition() implement a mapping from future_errc to that
...
4
...
6 errc Error Codes
Standard error_codes for the system_category() are defined by
alent to the POSIX-derived contents of :
enum class errc

enum class errc

Enumerators (§iso
...
5) (continues)

address_family_not_supported
address_in_use
address_not_available
already_connected
argument_list_too_long
argument_out_of_domain
bad_address
bad_file_descriptor
bad_message

EAFNOSUPPORT
EADDRINUSE
EADDRNOTAVAIL
EISCONN
E2BIG
EDOM
EFAULT
EBADF
EBADMSG

with values equiv-

Section 30
...
3
...
19
...
19
...
For systems supporting
POSIX-like facilities, they are also valid for the "generic" category: generic_category()
...
For example:
void problem(errc e)
{
if (e==EPIPE) {
//
...

}

// error : no conversion of errc to int

// error : broken_pipe not in scope

Section 30
...
3
...

}

Error Codes

883

// OK

}

30
...
3
...
30
...
1)

broken_promise
future_already_retrieved
promise_already_satisfied
no_state

1
2
3
4

These codes are valid for the "future" category: future_category()
...
4
...
8 io_errc Error Codes
Standard error_codes for the iostream_category() are defined by enum class io_errc:
enum class io_errc
stream

Enumerator (§iso
...
5
...


30
...
1, §30
...
1
...
1
...
1
...

[4] Use standard-library facilities as a model for flexible, widely usable software; §30
...
1
...
2
...
h is presented as a C++ standard-library header in ; §30
...

[7] Do not try to use a standard-library facility without #includeing its header; §30
...

[8] To use a range-for on a built-in array, #include; §30
...
2
...
4
...
(for
unexpected exceptions); §30
...
1
...
4
...
1
...
4
...
3
...
4
...

[14] Do not assume that assert() is always evaluated; §30
...
2
...
4
...


Chapter 30

31
STL Containers
It was new
...

It was simple
...
Nelson









Introduction
Container Overview
Container Representation; Element Requirements
Operations Overview
Member Types; Constructors, Destructor, and Assignments; Size and Capacity; Iterators;
Element Access; Stack Operations; List Operations; Other Operations
Containers
vector; Lists; Associative Containers
Container Adaptors
stack; queue; priority_queue
Advice

31
...
The rest of the STL is presented in Chapter 32 and Chapter 33
...
2 Container Overview
A container holds a sequence of objects
...
Operations on containers are summarized in §31
...


886

STL Containers

Chapter 31

Containers can be categorized like this:
• Sequence containers provide access to (half-open) sequences of elements
...

In addition, the standard library provides types of objects that hold elements while not offering all
of the facilities of sequence containers or associative containers:
• Container adaptors provide specialized access to underlying containers
...

The STL containers (the sequence and associative containers) are all resource handles with copy
and move operations (§3
...
1)
...
2) to
ensure that they interact properly with exception-based error handling
...
6
...
4)
...

};
A is defaulted to std::allocator (§34
...
1) which uses operator new() and operator delete() when it
needs to acquire or release memory for its elements
...
The sequence containers are contiguously allocated (e
...
, vector) or linked lists (e
...
, forward_list) of elements of their value_type (T
in the notation used above)
...

Unless you have a solid reason not to, use a vector
...
For
sequences of small elements, a vector can be an excellent representation for a data structure requiring list operations
...
In contrast, elements
of a list or an associative container do not move when new elements are inserted or other elements
are erased
...

An empty forward_list takes up only one word
...


Section 31
...
23
...
2)
is the type of the comparison; A is the allocator type

map
multimap
set
multiset

An ordered map from K to V; a sequence of (K,V) pairs
An ordered map from K to V; duplicate keys allowed
An ordered set of K
An ordered set of K; duplicate keys allowed

These containers are usually implemented as balanced binary trees (usually red-black trees)
...
4)
...
6
...
4)
...
4
...

H

Unordered Associative Containers (§iso
...
5
...
The default hash function
type, H, for a type K is std::hash (§31
...
3
...
The default for the equality function type, E, for a
type K is std::equal_to (§33
...

The associative containers are linked structures (trees) with nodes of their value_type (in the
notation used above, pair for maps and K for sets)
...
An unordered container need not have an ordering relation for
its elements (e
...
, <) and uses a hash function instead (§31
...
2
...
The sequence of an unordered
container does not have a guaranteed order
...

Container adaptors are containers providing specialized interfaces to other containers:
Container Adaptors
is the container type

C
priority_queue
queue
stack

Priority queue of Ts; Cmp is the priority function type
Queue of Ts with push() and pop()
Stack of Ts with push() and pop()

The default for a priority_queue’s priority function, Cmp, is std::less
...
See §31
...

Some data types provide much of what is required of a standard container, but not all
...
’’ The most interesting of those are:

888

STL Containers

Chapter 31

‘‘Almost Containers’’
T[N]
array
basic_string

string
u16string
u32string
wstring
valarray

A fixed-size built-in array: N contiguous elements of type T;
no size() or other member functions
A fixed-size array of N contiguous elements of type T;
like the built-in array, but with most problems solved
A contiguously allocated sequence of characters of type C
with text manipulation operations, e
...
, concatenation (+ and +=);
basic_string is typically optimized not to require free store for
short strings (§19
...
3)
basic_string
basic_string
basic_string
basic_string

bitset
vector

A numerical vector with vector operations, but with restrictions
to encourage high-performance implementations;
use only if you do a lot of vector arithmetic
A set of N bits with set operations, such as & and |
A specialization of vector with compactly stored bits

For basic_string, A is the allocator (§34
...
2
...

Prefer a container, such as vector, string, or array, over an array when you have a choice
...
g
...
2
...

Prefer the standard strings to other strings and to C-style strings
...
3
...


31
...
1 Container Representation
The standard doesn’t prescribe a particular representation for a standard container
...
Implementers will
choose appropriate and often cleverly optimized implementations to meet the general requirements
and common uses
...
4)
...
6)
...
2
...
3 and §23
...
Like vector, a string can grow into ‘‘free space’’ allocated
to avoid repeated reallocations:

string:

rep
characters

free space

Like a built-in array (§7
...


array

31
...
2 Element Requirements
To be an element of a container, an object must be of a type that allows the container implementation to copy or move it, and to swap elements
...
This roughly
means that any test for equality that you can devise on the value of the objects must deem the copy
equal to the original
...
Similarly, a move constructor and a move assignment must have the conventional definitions
and move semantics (§17
...
1)
...
If a type has copy or move, the standard-library swap() will work
...
23
...
3, §iso
...
2
...
17
...
3
...
Many basic algorithms, such as copy(), find(), and sort()
will work as long as the requirements for being a container element are met as well as the algorithm’s specific requirements (such as elements being ordered; §31
...
2
...

Some violations of the rules for standard containers can be detected by a compiler, but others
cannot and might then cause unexpected behavior
...
That would be bad design
(§13
...
1) and would violate the rules of the standard by not providing the basic guarantee (§13
...

An element in an invalid state could cause serious trouble later
...
The most obvious example is polymorphic types (§3
...
2,
§20
...
2)
...


Section 31
...
2
...
2
...
1 Comparisons
Associative containers require that their elements can be ordered
...
g
...
By default, the < operator is used to define the
order
...
4
...
4)
...
Informally, this means that both less-than and
equality (if defined) must be transitive
...

[2] Antisymmetry: cmp(x,y) implies !cmp(y,x)
...

[4] Transitivity of equivalence: Define equiv(x,y) to be !(cmp(x,y)||cmp(y,x))
...

The last rule is the one that allows us to define equality (x==y) as !(cmp(x,y)||cmp(y,x)) if we need ==
...
For example:
template
void sort(Ran first, Ran last);
// use < for comparison
template
void sort(Ran first, Ran last, Cmp cmp); // use cmp

The first version uses < and the second uses a user-supplied comparison cmp
...
We do that by defining a
function object (§3
...
3, §19
...
2) that does the comparison when invoked for a pair of strings:
class Nocase {
// case-insensitive string compare
public:
bool operator()(const string&, const string&) const;
};
bool Nocase::operator()(const string& x, const string& y) const
// return true if x is lexicographically less than y, not taking case into account
{
auto p = x
...
begin();
while (p!=x
...
end() && toupper(∗p)==toupper(∗q)) {
++p;
++q;
}
if (p == x
...
end();
if (q == y
...
Consider:
fruit:
apple pear Apple Pear lemon

892

STL Containers

Chapter 31

Sorting using sort(fruit
...
end(),Nocase()) would yield something like
fruit:
Apple apple lemon Pear pear

Assuming a character set in which uppercase letters precede lowercase letters, plain
sort(fruit
...
end()) would give:
fruit:
Apple Pear apple lemon pear

Beware that < on C-style strings (i
...
, const char∗s) compares pointer values (§7
...
Thus, associative containers will not work as most people would expect them to if C-style strings are used as
keys
...
For example:
struct Cstring_less {
bool operator()(const char∗ p, const char∗ q) const { return strcmp(p,q)<0; }
};
map m;

// map that uses strcmp() to compare const char* keys

31
...
2
...
When
the default isn’t right, a programmer can supply a comparison criterion
...
Instead, when a programmer supplies a comparison cmp,
equality is tested using two comparisons
...
It may look expensive, but
the library doesn’t check for equality very often, in about 50% of the cases only a single call of
cmp() is needed, and often the compiler can optimize away the double check
...
For example, associative containers (§31
...
3) compare keys
using an equivalence test !(cmp(x,y)||cmp(y,x))
...

For example, a multimap (§31
...
3) that uses case-insensitive comparison as its comparison criterion
will consider the strings Last, last, lAst, laSt, and lasT equivalent, even though == for strings deems
them different
...

If equals (by default ==) always gives the same result as the equivalence test !(cmp(x,y)||cmp(y,x))
(by default cmp() is <), we say that we have a total order
...
The standard library
defines them in the namespace std::rel_ops and presents them in (§35
...
3)
...
3

Operations Overview

893

31
...
A question mark (?) indicates a simplification: I have included operations that are provided
for only some of the containers
...

A forward_list does not provide insert(), erase(), or emplace(); instead, it provides the ∗_after
operations
...

• A forward_list does not provide reverse_iterator, const_reverse_iterator, rbegin(), rend(), crbegin(), crend(), or size()
...

The [] and at() operations are replicated simply to reduce the number of arrows
...
4
...
2
...

The standard-library operations have complexity guarantees:
Standard Container Operation Complexity

vector
list
forward_list
deque

[]
§31
...
2
const

const

List
§31
...
7
O(n)+
const
const
O(n)

Front
§31
...
2
const
const
const

stack

const
O(log(n))

queue
priority_queue
map
multimap
set
multiset

O(log(n))

unordered_map
unordered_multimap
unordered_set
unordered_multiset

const+

string
array

const
const
const
const
const

built-in array
valarray
bitset

O(log(n))+
O(log(n))+
O(log(n))+
O(log(n))+
const+
const+
const+
const+
O(n)+

O(n)+

Back
§31
...
6
const+
const
const
const
const
O(log(n))

const+

Iterators
§33
...
2
Ran
Bi
For
Ran

Bi
Bi
Bi
Bi
For
For
For
For
Ran
Ran
Ran
Ran

‘‘Front’’ operations refer to insertion and deletion before the first element
...

In the Iterators column, ‘‘Ran’’ means ‘‘random-access iterator,’’ ‘‘For’’ means ‘‘forward iterator,’’ and ‘‘Bi’’ means ‘‘bidirectional iterator’’ (§33
...
4)
...
3

Operations Overview

895

Other entries are measures of the efficiency of the operations
...
O(n) means the operation takes time proportional to the number of elements involved
...
For example, inserting an element into a list has a fixed cost (so it is listed as
const), whereas the same operation on a vector involves moving the elements following the insertion point (so it is listed as O(n))
...
The ‘‘big O’’ notation is conventional
...
A conventional term for O(n)+ is
amortized linear time
...
However, for large data structures const tends to mean ‘‘cheap,’’ O(n) to mean ‘‘expensive,’’
and O(log(n)) to mean ‘‘fairly cheap
...
For example:
Logarithm Examples
n
log(n)
n∗n

16
4
256

128
7
802,816

1,024
10
1,048,576

16,384
14
268,435,456

1,048,576
20
1
...
In particular, they must understand what elements are counted to get the n
...

The measures of complexity and cost are upper bounds
...
Naturally, implementers will try to do
better in important cases
...
Other factors, such as the cost of an individual operation on an element, may dominate
...
However, given modern machine architectures, getting to the next element through a link (in
a list) can be very much more expensive than getting to the next element of a vector (where the elements are contiguous)
...
Don’t just trust your intuition about cost and your complexity measures;
measure
...

The size() operation is constant time for all operations
...
A forward_list is optimized for space and does not store its size or a pointer to its last element
...
The ‘‘short string optimization’’ (§19
...
3) makes all
operations of short strings (e
...
, less than 14 characters) constant time
...
5
...
5
...


896

STL Containers

Chapter 31

31
...
1 Member Types
A container defines a set of member types:
Member types (§iso
...
2, §iso
...
3
...
1)
value_type
allocator_type
size_type
difference_type
iterator
const_iterator
reverse_iterator
const_reverse_iterator
reference
const_reference
pointer
const_pointer
key_type
mapped_type
key_compare
hasher
key_equal
local_iterator
const_local_iterator

Type of element
Type of memory manager
Unsigned type of container subscripts, element counts, etc
...
However, they
don’t provide types that are not meaningful
...


31
...
2 Constructors, Destructor, and Assignments
Containers provide a variety of constructors and assignment operations
...
g
...
3
...
˜C()
c2=c
c2=move(c)
c={elem}
c
...
assign(b,e)
c
...
4
...

Note that an assignment does not copy or move allocators
...

Allocators are described in §34
...

Remember that a constructor or an element copy may throw an exception to indicate that it cannot perform its tasks
...
3
...
3
...
1
...
assign(&vi[1],&vi[4]);

// vector initialized by five ints
// vector initialized by seven empty strings

// assign sequence of four ints to vi2
// assign the sequence 3,5,7 to vi2

vector vs2;
vs2 = {"The Eagle", "The Bird and Baby"};
vs2
...
Use () for size initializers and {} for every other kind
of iterator
...
However, because they
are resource handles (§31
...
1), we can return them (implicitly using move) efficiently
...
For example:

898

STL Containers

Chapter 31

void task(vector&& v);
vector user(vector& large)
{
vector res;
//
...

return res;
}

31
...
3 Size and Capacity
The size is the number of elements in the container; the capacity is the number of elements that a
container can hold before allocating more memory:
Size and Capacity
x=c
...
empty()
x=c
...
capacity()
c
...
resize(n)

c
...
shrink_to_fit()
c
...
capacity() equal to c
...
That
implies that iterators (and pointers and references) to elements may become invalid (i
...
, point to
the old element locations)
...
4
...
1
...
g
...
3
...
To contrast, an iterator to
an element of a sequence container (e
...
, a vector) is invalidated if the elements are relocated (e
...
,
by a resize(), reserve(), or push_back()) or if the element to which it points is moved within the container (e
...
, by an erase() or insert() of an element with a lower index)
...
4
...
1) are so effective that performance is rarely a good reason to use reserve()
...


Section 31
...
4

Iterators

899

31
...
4 Iterators
A container can be viewed as a sequence either in the order defined by the containers iterator or in
the reverse order
...
begin()
p=c
...
cbegin()
p=c
...
rbegin()
p=c
...
crbegin()
p=c
...
The simplest way of doing that is by a range-for (§9
...
1) which implicitly uses begin() and
end()
...
begin() and v
...
In such cases, auto is useful to minimize source
code size and eliminate opportunities for typos
...
begin(); p!=end(); ++p) {
if (p!=v
...
That is, I should have
written:
for (auto p = v
...
cbegin() && ∗(p−1)==∗p)
cout << "duplicate " << ∗p << '\n';
}

// use const iterators

For most containers and most implementations, using begin() and end() repeatedly is not a performance problem, so I did not bother to complicate the code like this:
auto beg = v
...
cend();
for (auto p = beg; p!=end; ++p) {
if (p!=beg && ∗(p−1)==∗p)
cout << "duplicate " << ∗p << '\n';
}

900

STL Containers

Chapter 31

31
...
5 Element Access
Some elements can be accessed directly:
Element Access
c
...
back()
c[i]
c
...
at(k)

Reference to first element of c; not for associative containers
Reference to last element of c; not for forward_list or associative containers
Reference to the ith element of c; unchecked access;
not for lists or associative containers
Reference to the ith element of c; throw an out_of_range if i is out of range;
not for lists or associative containers
Reference to the element with key k of c; insert (k,mapped_type{}) if not found;
for map and unordered_map only
Reference to the ith element of c; throw an out_of_range if k is not found;
for map and unordered_map only

Some implementations – especially debug versions – always do range checking, but you cannot
portably rely on that for correctness or on the absence of checking for performance
...

The associative containers map and unordered_map have [] and at() that take arguments of the
key type, rather than positions (§31
...
3)
...
3
...
push_back(x)
c
...
emplace_back(args)

Add x to c (using copy or move) after the last element
Remove the last element from c
Add an object constructed from args to c after the last element

A c
...
If we run out of memory or
x’s copy constructor throws an exception, c
...
A failed push_back() has no effect
on the container: the strong guarantee is offered (§13
...

Note that pop_back() does not return a value
...

In addition, list and deque provide the equivalent operations on the start (front) of their
sequences (§31
...
2)
...

The push_back() is a perennial favorite for growing a container without preallocation or chance
of overflow, but emplace_back() can be used similarly
...
emplace_back(re,im);

// read two doubles
// add complex{re,im} at the end

Section 31
...
7

List Operations

901

31
...
7 List Operations
Containers provide list operations:
List Operations
q=c
...
insert(p,n,x)
q=c
...
insert(p,{elem})

q=c
...
erase(p)
q=c
...
clear()

Add x before p; use copy or move
Add n copies of x before p; if c is an
associative container, p is a hint of where to start searching
Add elements from [first:last) before p;
not for associative containers
Add elements from initializer_list {elem} before p; p is a hint of
where to start searching for a place to put the new element;
for ordered associative containers only
Add element constructed from args before p;
not for associative containers
Remove element at p from c
Erase [first:last) of c
Erase all elements of c

For insert() functions, the result, q, points to the last element inserted
...

For containers with contiguous allocation, such as vector and deque, inserting and erasing an
element can cause elements to be moved
...
An element is moved if its position is after the insertion/deletion point or if all elements
are moved because the new size exceeds the previous capacity
...
begin()+2;
v
...
begin()+2;
auto p2 = v
...
erase(v
...
6
...

The emplace() operation is used when it is notationally awkward or potentially inefficient to first
create an object and then copy (or move) it into a container
...
begin();
while (p!=lst
...
emplace(p,"England",7
...
insert(p,make_pair("France",9
...
insert(p,pair>{"Greece",3
...
Such an operation could not be implemented because there is no general way of

902

STL Containers

Chapter 31

finding the previous element in a forward_list given only an iterator
...
Similarly, unordered containers use emplace_hint() to provide a hint rather than ‘‘plain’’ emplace()
...
3
...
swap(c2)
swap(c1,c2)

Do all corresponding elements of c1 and c2
!(c1==c2)
Is c1 lexicographically before c2?
!(c2c2!(c1Exchanges values of c1 and c2; noexcept
c1
...
g
...
g
...

The swap() operations exchange both elements and allocators
...
4 Containers
This section goes into more detail about:
• vector, the default container (§31
...
1)
• The linked lists: list and forward_list (§31
...
2)
• The associative containers, such as map and unordered_map (§31
...
3)

31
...
1 vector
The STL vector is the default container
...
If your suggested alternative is a list or a built-in array, think twice
...
3 describes the operations on vector and implicitly contrasts them with what is provided for
other containers
...

The vector’s template argument and member types are defined like this:
template>
class vector {
public:
using reference = value_type&;
using const_reference = const value_type&;
using iterator = /* implementation-defined */;
using const_iterator = /* implementation-defined */;

Section 31
...
1

vector

903

using size_type = /* implementation-defined */;
using difference_type = /* implementation-defined */;
using value_type = T;
using allocator_type = Allocator;
using pointer = typename allocator_traits::pointer;
using const_pointer = typename allocator_traits::const_pointer;
using reverse_iterator = std::reverse_iterator;
using const_reverse_iterator = std::reverse_iterator;
//
...
4
...
1 vector and Growth
Consider the layout of a vector object (as described in §13
...
6)
...
I used to be careful about using reserve() when I was reading into a vector
...
The default growth strategy worked just as well as my estimates, so I stopped trying
to improve performance using reserve()
...

The notion of capacity allows for iterators into a vector to be valid unless a reallocation actually
happens
...
reserve(max);
vector words;
bool in_word = false;
for (char c; cin
...
push_back(0);
// end of previous word
chars
...
push_back(&chars
...
push_back(c);
}
else
in_word = false;
}
if (in_word)
chars
...
size()) {
//
...
shrink_to_fit();

// terminate last word

// oops: chars grew beyond capacity; the words are invalid

// release any sur plus capacity

Had I not used

reserve() here, the pointers in words would have been invalidated if
caused a relocation
...
They may – or may not – point to an element, but almost certainly
not to the elements they pointed to before the relocation
...
5) is as unnecessary as it is tedious and error-prone
...
push_back()

31
...
1
...

The amount of memory consumed by a vec of type vector is roughly
sizeof(vector)+vec
...
The sizeof(vector) is about 12 bytes, which is
insignificant for larger vectors
...
To get to the next element, the code does not have to indirect through a pointer, and modern machines are optimized for consecutive access through a
vector-like structure
...

• vector supports simple and efficient random access
...

It is easy to underestimate these benefits
...
The effect can be so spectacular and surprising that I suggest you test it
yourself [Stroustrup,2012a]
...
4
...
2

vector

and Nesting

905

The benefits of compactness and efficiency of access can be unintentionally compromised
...
There are two obvious alternatives:
• A vector of vectors: vector> accessed by C-style double subscripting: m[i][j]
• A specific matrix type, Matrix<2,double> (Chapter 29), that stores elements contiguously
(e
...
, in a vector) and computes locations in that vector from a pair of indices: m(i,j)
The memory layout for a 3-by-4 vector> looks like this:

The memory layout for Matrix<2,double> looks like this:

To construct the vector>, we need four constructor calls with four free-store allocation operations
...

To construct the Matrix<2,double>, we need one constructor call with one free-store allocation
...

Once we reach an element of a row, we don’t need a further indirection to access its successor,
so access to the vector> is not always twice as costly as access to Matrix<2,double>
...

The vector> solution implies the possiblity of the row having different sizes
...

The problems and overhead get worse when we need higher dimensions: compare the number
of added indirections and allocations for a vector>> and a Matrix<3,double>
...
The advantages are logical as well as performance related
...
For example, consider the development complexities, run-time costs, memory costs, and opportunities for errors in
an implementation of a two-dimensional structure when the rows are implemented as independent
objects on the free store: vector∗>
...
4
...
3 vector and Arrays
A vector is a resource handle
...
However, that occasionally puts it at a disadvantage compared to data structures (such
as built-in arrays and array) that do not rely on storing elements separately from a handle
...

A vector deals with properly initialized objects
...
However, that occasionally puts it at a disadvantage compared to data structures (such as built-in arrays and array) that allow uninitialized elements
...
get(&x);
}

For

vector,
MAX)
...
4
...
4 vector and string
A vector is a resizable, contiguous sequence of chars, and so is a string
...
It makes no assumptions about the relationships among the values stored in it
...
Sorting them into !,HWdellloor (preceded by a space) makes sense
...
The relationships among the characters
are assumed to be important
...
Some string operations reflect that (e
...
, c_str(), >>, and find() ‘‘know’’ that Cstyle strings are zero-terminated)
...
For example, the short-string optimization (§19
...
3) would be a pure pessimization
if it wasn’t for the fact that we use many short strings, so that minimizing free-store use becomes
worthwhile
...


31
...
2 Lists
The STL provides two linked-list types:
• list: a doubly-linked list
• forward_list: a singly-linked list
A list is a sequence optimized for insertion and deletion of elements
...
In particular, iterators referring to other elements are not affected
...
4
...
If necessary, use advance() and similar operations to navigate lists (§33
...
4)
...
1
...

By default, list elements are individually allocated in memory and include predecessor and successor pointers (§11
...
2)
...

A forward_list is a singly-linked list
...
For compactness, forward_list
doesn’t even provide a size(); an empty forward_list takes up just one word of memory
...
If there are enough elements to
make counting them expensive, maybe you should use a different container
...
4)
...
23
...
4
...
23
...
5
...
push_front(x)
lst
...
emplace_front(args)
lst
...
remove_if(f)
lst
...
unique(f)
lst
...
merge(lst2,f)
lst
...
sort(f)
lst
...
For example:
void use()
{
list lst {2,3,2,3,5};
lst
...
unique();
cout << lst
...
5), the member algorithms really

// lst is now {2,2,5}
// lst is now {2,5}
// writes 2

The merge() algorithm is stable; that is, equivalent elements keep their relative order
...
23
...
5
...
end()

p
lst
...
splice(p,lst2,p2)
lst
...
For
example:
list lst1 {1,2,3};
list lst2 {5,6,7};
auto p = lst1
...
begin();
++q;

// q points to 6

lst1
...
23
...
4
...
emplace_after(p,args)
p2=lst
...
insert_after(p,n,x)
p2=lst
...
insert_after(p,{elem})
p2=lst
...
erase_after(b,e)
lst
...
splice_after(p,b,e)
lst
...
splice_after(p,lst2,b,e)

Emplace element constructed from args after p;
p2 points to the new element
Insert x after p; p2 points to the new element
Insert n copies of x after p;
p2 points to the last new element
Insert [b:e) after p; p2 points to the last new element
Insert {elem} after p;
p2 points to the last new element; elem is an initializer_list
Erase the element after p;
p2 points to the element after p or lst
...


Section 31
...
3

Associative Containers

909

31
...
3 Associative Containers
Associative containers provide lookup based on keys
...
They are implemented as balanced binary trees, usually red-black trees
...
They are implemented as hash tables with linked overflow
...
‘‘Plain’’ is never spelled out, so the associative containers are:
Associative Containers (§iso
...
4
...
23
...
1)
set
map

multiset
multimap

unordered_set
unordered_map

unordered_multiset
unordered_multimap

Their template arguments are described in §31
...

Internally, a map and an unordered_map are very different
...
2
...
In particular, map uses its comparison criterion (typically <) on a key to search through a balanced tree (an O(log(n)) operation), whereas unordered_map applies a hash function on a key to find
a slot in a hash table (an O(1) operation for a good hash function)
...
4
...
1 Ordered Associative Containers
Here are the template arguments and member types for map:
templatetypename T,
typename Compare = less,
typename Allocator = allocator>>
class map {
public:
using key_type = Key;
using mapped_type = T;
using value_type = pair;
using key_compare = Compare;
using allocator_type = Allocator;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = /* implementation-defined */ ;
using const_iterator = /* implementation-defined */ ;
using size_type = /* implementation-defined */ ;
using difference_type = /* implementation-defined */ ;

910

STL Containers

Chapter 31

using pointer = typename allocator_traits::pointer;
using const_pointer = typename allocator_traits::const_pointer;
using reverse_iterator = std::reverse_iterator;
using const_reverse_iterator = std::reverse_iterator;
class value_compare { /* operator()(k1,k2) does a key_compare()(k1,k2) */ };
//
...
3
...
23
...
4
...
23
...
4
...
at(k)

v is a reference to the element with key k;
if k is not found, {k,mapped_type{}} is inserted into c;
only for map and unordered_map
v is a reference to the element with key k;
if k is not found, an out_of_range is thrown;
only for map and unordered_map

Section 31
...
3
...
23
...
4
...
find(k)
p=c
...
upper_bound(k)
pair(p1,p2)=c
...
insert(x)

p2=c
...
insert(b,e)
c
...
emplace(args)
p=c
...
key_comp()
r=c
...
count(k)

points to the first element with key k or c
...
end();
ordered containers only
p points to the first element with key >k or c
...
lower_bound(k); p2=c
...
g
...
g
...
insert(∗p) for every p in [b:e)
Insert each element of the initializer_list args;
an element is of type pair
p points to an object of c’s value_type constructed
from args and inserted into c
p points to an object of c’s value_type constructed
from args and inserted into c;
h is an iterator into c, possibly used as a hint of
where to start to search for a place for the new entry
r is a copy of the key comparison object;
ordered containers only
r is a copy of the value comparison object;
ordered containers only
n is the number of elements with key k
p
p

Operations specific to unordered containers are presented in §31
...
3
...

If a key, k, is not found by a subscript operation, m[k], a default value is inserted
...


912

STL Containers

Chapter 31

If that is not the desired behavior, we can use find() and insert() directly:
auto q = dictionary
...
end()) {
cout << "entry not found";
dictionary
...
The result of m[k] is equivalent to the
result of (∗(m
...
first))
...

The insert(make_pair()) notation is rather verbose
...
emplace("sea cow","extinct");

Depending on the quality of the optimizer, this may also be more efficient
...
If you want to have more than one value for a single key, use a multimap
...
2
...
1) returned by equal_range() is lower_bound() and the second upper_bound()
...
equal_range(k);
if (pp
...
second)
cout << "no element with value '" << k << "'\n";
else {
cout << "elements with value '" << k << "':\n";
for (auto p=pp
...
second; ++p)
cout << p−>second << ' ';
}

This prints 2 7 9
...
lower_bound(),m
...


However, that would imply an extra traversal of the map
...
6)
...
For a set, the value_type is also the
key_type
...
4
...
1

Ordered Associative Containers

913

To have a set, we need to provide a comparison function
...
label ...
label << ':' << r
...
23
...
4)
...
We cannot even change a member of an element that takes no part in the
comparison
...
value;
}

// error: set elements are immutable

If you need to modify an element, use a map
...


31
...
3
...
For simple uses, there are few differences from (ordered) containers because the associative containers share most operations (§31
...
3
...
For example:
unordered_map score1 {
{"andy", 7}, {"al",9}, {"bill",−3}, {"barbara",12}
};
map score2 {
{"andy", 7}, {"al",9}, {"bill",−3}, {"barbara",12}
};
template
ostream& operator<<(ostream& os, pair& p)
{
return os << '{' << p
...
second << '}';
}

914

STL Containers

Chapter 31

void user()
{
cout <<"unordered: ";
for (const auto& x : score1)
cout << x << ", ";
cout << "\nordered: ";
for (const auto& x : score2)
cout << x << ", ";
}

The visible difference is that iteration through a map is ordered and for an unordered_map it is not:
unordered: {andy,7}, {al,9}, {bill,−3}, {barbara,12},
ordered: {al,9}, {andy, 7}, {barbara,12}, {bill,−3},

Iteration over an unordered_map depends on the order of insertion, the hash function, and the load
factor
...


31
...
3
...

};

By default, an unordered_map uses hash for hashing and equal_to to compare keys
...
4
...
3

Constructing unordered_maps

915

The default equal_to (§33
...

The general (primary) template hash doesn’t have a definition
...
For common types, such as string, standard hash specializations are provided, so the user need not provide them:
Types with hash (§iso
...
8
...
g
...
17
...
3
...
Two calls of a hash function for the
same value must give the same result, and ideally such results are uniformly distributed over the set
of size_t values so as to minimize the chances that h(x)==h(y) if x!=y
...
Fortunately, there is a pattern:
unordered_map
unordered_map m {n,hf,eql,a};

unordered_map m {n,hf,eql};
unordered_map m {n,hf};
unordered_map m {n};
unordered_map m {};

Constructors (§iso
...
5
...

unordered_map

Constructors (§iso
...
5
...
The number of elements will be then number of elements in [b:e), distance(b,e)
...
23
...
4)

unordered_map m {{elem},n,hf,eql,a};

Construct m from the elems of an initializer_list,
using n buckets,
the hash function hf, the equality function eql,
and the allocator a

unordered_map m {{elem},n,hf,eql};
unordered_map m {{elem},n,hf};
unordered_map m {{elem},n};
unordered_map m {{elem}};

unordered_map m {{elem},n,hf,eql,allocator_type{}};
unordered_map m {{elem},n,hf,key_equal{}};
unordered_map m {{elem},n,hasher{}};
unordered_map m {{elem},N};
the bucket count N is implementation-defined

Here, we get the initial elements from a sequence from a {}-delimited initializer list of elements
...

Finally, unordered_map has copy and move constructors, and also equivalent constructors that
supply allocators:
unordered_map
unordered_map m {m2};
unordered_map m {a};
unordered_map m {m2,a};

Constructors (§iso
...
5
...
There are many possible combinations of types, and mistakes can lead to strange error messages
...
Try something like:
unordered_map um {100,My_hasher}; // OK

31
...
3
...
In fact, there are several ways to do that
...
Here, I present several versions, starting with the most explicit
and ending with the simplest
...
4
...
4

Hash and Equality Functions

917

size_t operator()(const Record& r) const
{
size_t h = 0;
for (auto x : r
...
name
...
name
...
name
...
name[i])!=toupper(r2
...
name << ',' << r
...
By default, the
unordered_set uses the default versions:
unordered_set m {
{"andy", 7}, {"al",9}, {"bill",−3}, {"barbara",12}
// use Nocase_hash{} and Nocase_equal{}
};

Often, the easiest way of writing a hash function is to use the standard-library hash functions provided as specializations of hash (§31
...
3
...
For example:
size_t hf(const Record& r) { return hash()(r
...
val); };
bool eq (const Record& r, const Record& r2) { return r
...
name && r
...
val; };

Combining hash values using exclusive OR (ˆ) preserves their distributions over the set of values of
type size_t (§3
...
5, §10
...
1)
...
name << ',' << r
...

If we don’t have an initializer list handy, we can give an initial size instead:
unordered_set m {10,hf,eq};

That also makes it a bit easier to focus on the hash and equality operations
...
name)ˆhash{}(r
...
name==r2
...
val==r2
...

However, here, function may incur overhead that I would prefer to avoid if the unordered_set
was heavily used
...
name)ˆhash()(r
...
name==r2
...
val==r2
...
name)ˆhash{}(r
...
4
...
4

Hash and Equality Functions

919

template<>
struct equal_to {
bool operator()(const Record& r, const Record& r2) const
{
return r
...
name && r
...
val;
}
};
}
unordered_set m1;
unordered_set m2;

The default hash and hashes obtained from it by using exclusive-or are often pretty good
...


31
...
3
...
Keys with the same hash value are said to be ‘‘in the same bucket’’ (see §31
...
1)
...
23
...
5)
is c’s hash function

h=c
...
key_eq()
d=c
...
size())/c
...
max_load_factor()
c
...
rehash(n)
c
...
rehash(ceil(n/c
...
For example, if the capacity() is 100 elements and the size() is 30, the load_factor() is 0
...

Note that setting the max_load_factor, calling rehash(), or calling reserve() can be very expensive
operations (worst case O(n∗n)) because they can – and in realistic scenarios typically do – cause
rehashing of all elements
...
For example:
unordered_set ...

constexpr int expected = 1000000;
// expected maximum number of elements
people
...
7);
// at most 70% full
people
...
7) is often a good choice
...
23
...
5)
n=c
...
max_bucket_count()
m=c
...
bucket(k)
p=c
...
end(n)
p=c
...
cend(n)

n is the number of buckets in c (the size of the hash table);
noexcept
n is the largest possible number of elements in a bucket;
noexcept
m is the number of elements in the nth bucket
An element with key k would be in the ith bucket
p points to the first element in bucket n
p points to the one-past-the-last element in bucket n
p points to the first element in bucket n;
p is a const iterator
p points to the one-past-the-last element in bucket n;
p is a const iterator

Use of an n for which c
...

One use for the bucket interface is to allow experimentation with hash functions: a poor hash
function will lead to large bucket_count()s for some key values
...


31
...
Container
adaptors are intended to be used only through their specialized interfaces
...
They do not offer iterators or subscripting
...


31
...
1 stack
The stack container adaptor is defined in
...
23
...
5
...
5
...
empty(); }
size_type size() const { return c
...
back(); }
const_reference top() const { return c
...
push_back(x); }
void push(value_type&& x) { c
...
pop_back(); }
// pop the last element
template ...
args)
{
c
...
);
}
void swap(stack& s) noexcept(noexcept(swap(c, s
...
c);
}
protected:
C c;
};

That is, a stack is an interface to a container of the type passed to it as a template argument
...

In addition, stack provides the usual comparison operators (==, <, etc
...

By default, a stack makes a deque to hold its elements, but any sequence that provides back(),
push_back(), and pop_back() can be used
...

Elements are added to a stack using push_back() on the underlying container
...
On the other hand, a stack can underflow:
void f()
{
stack s;
s
...
empty()) {
// don’t pop
}
else {
s
...
pop();
}
}

// underflow is preventable

// but not impossible
// fine: s
...
Instead, the top() is accessed and then pop()ed when it is no
longer needed
...
For example:
void f(stack& s)
{
if (s
...
pop();
//
...
If that’s not enough, there
are a handful of constructors for supplying another
...
5
...
23
...
3
...
like stack
...
pop_front(); }
// pop the first element
};

Queues seem to pop up somewhere in every system
...
empty()) {
Message mess;
{
lock_guard lck(m); // lock while extracting message
if (q
...
5
...
front();
q
...
5
...
The declaration of priority_queue is much like the declaration of queue with additions to deal with a comparison object and a couple of constructors initializing from a sequence:
template, typename Cmp = less>
class priority_queue {
// §iso
...
6
...

};

The declaration of priority_queue is found in
...
priority; }
//
...
empty()) {
Message mess;
{
lock_guard lck(m); // hold lock while extracting message
if (q
...
top();
q
...
5
...
The order in which elements with equal priority come to the head of the queue is not defined
...
2
...
1)
...
One useful way of
implementing a priority_queue is to use a tree structure to keep track of the relative positions of elements
...
A priority_queue is almost certainly
implemented using a heap (§32
...
4)
...
6 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]
[14]
[15]
[16]
[17]
[18]
[19]
[20]
[21]
[22]
[23]
[24]
[25]

An STL container defines a sequence; §31
...

Use vector as your default container; §31
...
4
...
2, §31
...
1
...

Use forward_list for sequences that are usually empty; §31
...
4
...

When it comes to performance, don’t trust your intuition: measure; §31
...

Don’t blindly trust asymptotic complexity measures; some sequences are short and the cost
of individual operations can vary dramatically; §31
...

STL containers are resource handles; §31
...
1
...
2
...
4
...

An unordered_map is a hash table; §31
...
1, §31
...
3
...

To be an element type for a STL container, a type must provide copy or move operations;
§31
...
2
...
2
...

Comparison operations should implement a strict weak order; §31
...
2
...

Pass a container by reference and return a container by value; §31
...
2
...
3
...

For simple traversals of a container, use a range-for loop or a begin/end pair of iterators;
§31
...
4
...
3
...

Use auto to avoid verbosity and typos when you use iterators; §31
...
4
...
3
...
4
...

Don’t assume performance benefits from reserve() without measurement; §31
...
3
...
3
...
4
...
1
...
3
...

When necessary, use reserve() to make performance predictable; §31
...
3
...
2
...

Use at() when you need guaranteed range checks; §31
...
2
...
3
...


Section 31
...
4
...
2
...
4
...
3
...
4
...

A list usually has a four-word-per-element memory overhead; §31
...
2
...
4
...
1
...
4
...
2
...
3
...
g
...
4
...

Use ordered associative containers (e
...
, map and set) if you need to iterate over their elements in order; §31
...
3
...

Experiment to check that you have an acceptable hash function; §31
...
3
...

Hash function obtained by combining standard hash functions for elements using exclusive
or are often good; §31
...
3
...

0
...
4
...
5
...
5
...
5
...

– Engineer´s proverb










Introduction
Algorithms
Sequences; Policy Arguments; Complexity
Nonmodifying Sequence Algorithms
for_each(); Sequence Predicates; count(); find(); equal() and mismatch(); search()
Modifying Sequence Algorithms
copy(); unique(); remove() and replace(); rotate(), random_shuffle(), and partition(); Permutations; fill(); swap()
Sorting and Searching
Binary Search; merge(); Set Algorithms; Heaps; lexcographical_compare()
Min and Max
Advice

32
...
The STL consists of the iterator, container, algorithm,
and function object parts of the standard library
...


32
...
They operate on sequences defined
by a pair of iterators (for inputs) or a single iterator (for outputs)
...
,
two sequences, the first is represented by a pair of iterators, [b:e), but the second by just a single

928

STL Algorithms

Chapter 32

iterator, b2, which is considered the start of a sequence holding sufficient elements for the algorithm, for example, as many elements as the first sequence: [b2:b2+(e−b))
...
Many algorithms follow the usual convention of returning the end of a sequence to represent ‘‘not found’’ (§4
...
I don’t mention that for
each algorithm
...

• Each can be widely used and known by many programmers
...
If you find yourself writing a
piece of code with several loops, local variables that don’t seem to relate to each other, or complicated control structures, consider if the code could be simplified by making a part into a function/algorithm with a descriptive name, a well-defined purpose, a well-defined interface, and welldefined dependencies
...
6
...
2
...
The iterator-based interfaces are a good, but not perfect, approximation to that ideal (§33
...
1)
...
begin(),v1
...
begin());
// may overflow v2
sort(v1
...
end());
// oops!
}

Many such problems can be alleviated by providing container versions of the standard-library algorithms
...
2
...
size() ...
begin(),source
...
begin());
}

This would simplify the definition of user(), make the second error impossible to express, and catch
the first at run time:
void user(vector& v1, vector& v2)
{
copy(v1,v2); // overflows will be caught
sort(v1);
}

However, the container versions are also less general than the versions that use iterators directly
...

A complementary approach is to define a ‘‘range’’ or ‘‘sequence’’ abstraction that allows us to
define sequences when needed
...
4
...
That is, there is no Range class holding data – exactly as there is no Iterator
class or Container class in the STL
...

The standard-library containers mostly return iterators
...
One reason for that is that when the STL was
designed, there was no direct support for move semantics
...
Some programmers used explicit indirection (e
...
, a
pointer, reference, or iterator) or some clever trickery
...
push_back(&x);
return res;
}

In C++98, this find_all() would have been a bad performance bug whenever the number of matches
was large
...

Note that whatever an STL algorithm returns, it cannot be an argument container
...
Iterators exist primarily to isolate algorithms from the data
structure on which they operate, and vice versa
...
3 Policy Arguments
Most standard-library algorithms come in two versions:
• A ‘‘plain’’ version that performs its action using conventional operations, such as < and ==
• A version that takes key operations as arguments
For example:
template
void sort(Iter first, Iter last)
{
//
...

}
template
void sort(Iter first, Iter last, Pred pred)
{
//
...

}

This greatly increases the flexibility of the standard library and its range of uses
...
For example:
template>>
sort(Ran first, Ran last, Pred pred ={})
{
//
...

}

// use a default template argument

The difference between having two functions and having one with a default argument can be
observed by someone taking pointers to functions
...

In some cases, an argument could be interpreted as either a predicate or a value
...

To simplify the task for the programmer, the _if suffix is often used to indicate that an algorithm
takes a predicate
...
Consider:
using Predicate = bool(∗)(int);

Section 32
...
begin(),v1
...
begin(),v2
...
g
...
4
...
g
...
Unless otherwise stated, assume that a policy argument passed to
an algorithm should not modify an element
...
begin(),v
...
If you are really sneaky,
you could even modify the sequence (e
...
, by inserting or removing an element using the name of a
container being iterated over), so that the iteration would fail (probably in obscure ways)
...

Similarly, a predicate should not carry state that changes the meaning of its operation
...
Some function objects passed to algorithms, such
as random number generators, do carry mutable state
...

The == and < operations on pointer elements are rarely appropriate for an STL algorithm: they
compare machine addresses rather than the values pointed to
...
6)
...
3
...
3), the complexity of algorithms is specified by the standard
...

Algorithm Complexity (§iso
...
For example, if n<3, a quadratic algorithm may be the best choice
...
For example, traversing a list can be much slower than

932

STL Algorithms

Chapter 32

traversing a vector, even though the complexity in both cases is linear (O(n))
...


32
...
Typically, user-supplied operations to an algorithm don’t change the values of elements either; they tend to be predicates (which
may not modify their arguments)
...
4
...
25
...
4)

Do f(x) for each x in [b:e); return f

When possible, prefer a more specific algorithm
...
For example:
void increment_all(vector& v) // increment each element of v
{
for_each(v
...
end(), [](int& x) {++x;});
}

32
...
2 Sequence Predicates
Sequence Predicates (§iso
...
2
...
size() ...
begin(),div
...
size());
for (int i = 0; i ...


Section 32
...
3

count()

933

32
...
3 count()
count
x=count(b,e,v)
x=count_if(b,e,v,f)

x
x

(§iso
...
2
...
begin(),s
...
begin(),s
...

}

The isspace() predicate (§36
...


32
...
4 find()
The find() family of algorithms do linear searches for some element or predicate match:
The find Family (§iso
...
2
...


points to the first element in [b:e) such that ∗p==v
points to the first element in [b:e) such that f(∗p)
p points to the first element in [b:e) such that !f(∗p)
p points to the first element in [b:e) such that ∗p==∗q
for some q in [b2:e2)
p points to the first element in [b:e) such that f(∗p,∗q)
for some q in [b2:e2)
p points to the first element in [b:e) such that ∗p==∗(p+1)
p points to the first element in [b:e) such that f(∗p,∗(p+1))
p points to the last ∗p in [b:e) such that ∗p==∗q for
an element ∗q in [b2:e2)
p points to the last ∗p in [b:e) such that f(∗p,∗q) for
an element ∗q in [b2:e2)
p
p

find_if()

return an iterator to the first element that matches a value and a

void f(const string& s)
{
auto p_space = find(s
...
end(),' ');
auto p_whitespace = find_if(s
...
end(), isspace);
//
...
For example:

934

STL Algorithms

Chapter 32

array x = {1,3,4 };
array y = {0,2,3,4,5};
void f()
{
auto p = find_first_of(x
...
end(),y
...
end);
auto q = find_first_of(p+1,x
...
begin(),y
...


x[1]

because

3

is the first element of

// p = &x[1]
// q = &x[2]
x

with a match in y
...
4
...
25
...
11, §iso
...
2
...
No end is specified for the second sequence; that is, there is no
last2
...
This technique is used throughout the standard
library, where pairs of sequences are used for operations on pairs of elements
...
4) and the type function Value_type (§28
...
1)
...
4
...
4
...
25
...
13)
p=search(b,e,b2,e2)
p=search(b
...
If that second
sequence is found, an iterator for the first matching element in the first sequence is returned
...
’’ For example:
string quote {"Why waste time learning, when ignorance is instantaneous?"};
bool in_quote(const string& s)
{
auto p = search(quote
...
end(),s
...
end()); // find s in quote
return p!=quote
...

Use find() or binary_search() (§32
...


32
...

transform
p=transform(b,e,out,f)
p=transform(b,e,b2,out,f)

(§iso
...
3
...
Instead, it produces an output that is a transformation of its input based on a user-supplied operation
...
begin(),s
...
begin(),toupper);
}

This really transforms the input s
...
5
...
The following sections list versions of copy() combined with other algorithms, such as replace_copy() (§32
...
3)
...
25
...
1)
p=copy(b,e,out)
p=copy_if(b,e,out,f)
p=copy_n(b,n,out)
p=copy_backward(b,e,out)
p=move(b,e,out)
p=move_backward(b,e,out)

Copy all elements in [b:e) to [out:p); p=out+(e−b)
Copy elements x in [b:e) for which f(x) to [out:p)
Copy the first n elements in [b:b+n) to [out:p); p=out+n
Copy all elements in [b:e) to [out:p),
starting with its last element; p=out+(e−b)
Move all elements in [b:e) to [out:p); p=out+(e−b)
Move all elements in [b:e) to [out:p),
starting with its last element; p=out+(e−b)

The target of a copy algorithm need not be a container
...
5) will do
...
begin(),lc
...
To
write, we need only an iterator describing where to write to
...
One way to ensure that we don’t do this is to use an inserter
(§33
...
2) to grow the target as needed
...
5
...
begin(),vs
...
begin());
// might overwrite end of v
copy(vs
...
end(),back_inserter(v)); // add elements from vs to end of v
}

The input sequence and the output sequence may overlap
...

We use copy_if() to copy only elements that fulfill some criterion
...
begin(),ld
...


32
...
2 unique()
The unique() algorithm removes adjacent duplicate elements from a sequence:
The unique Family (§iso
...
3
...
For example:
void f(list& ls, vector& vs)
{
ls
...
4
...
begin(),ls
...
I used sort() to get equal strings adjacent
...
It does not know which container
these iterators point into, so it cannot modify that container
...
This implies that unique() does not eliminate duplicates from its input sequence in the
way we naively might expect
...
begin(),vs
...
begin(),vs
...
For example:
int main()
{
string s ="abbcccde";
auto p = unique(s
...
end());
cout << s << ' ' << p−s
...

Algorithms that might have removed elements (but can’t) generally come in two forms: the
‘‘plain’’ version that reorders elements in a way similar to unique() and a _copy version that produces a new sequence in a way similar to unique_copy()
...
begin(),c
...
begin(),c
...
erase(p,c
...
erase(unique(c
...
end()),c
...


32
...
3 remove() and replace()
The remove() algorithm ‘‘removes’’ elements to the end of a sequence:
remove
p=remove(b,e,v)
p=remove_if(b,e,v,f)
p=remove_copy(b,e,out,v)
p=remove_copy_if(b,e,out,f)
reverse(b,e)
p=reverse_copy(b,e,out)

(§iso
...
3
...
5
...
25
...
5)

Replace elements ∗p in [b:e) for which ∗p==v with v2
Replace elements ∗p in [b:e) for which f(∗p) with v2
Copy [b:e) to [out:p),
replacing elements for which ∗p==v with v2
Copy [b:e) to [out:p),
replacing elements for which f(∗p,v) with v2

replace(b,e,v,v2)
replace_if(b,e,f,v2)
p=replace_copy(b,e,out,v,v2)
p=replace_copy_if(b,e,out,f,v2)

These algorithms cannot change the size of their input sequence, so even remove() leaves the size of
its input sequence unchanged
...
For
example:
string s {"∗CamelCase∗IsUgly∗"};
cout << s << '\n';
auto p = remove(s
...
end(),'∗');
copy(s
...
5
...


(§iso
...
3
...
25
...
12)

Shuffle elements of [b:e), using
the default random number generator
Shuffle elements of [b:e), using
the random number generator f
Shuffle elements of [b:e), using
the uniform random number generator f

A shuffle algorithm shuffles its sequence much in the way we would shuffle a pack of cards
...

By default, random_shuffle() shuffles its sequence using a uniform distribution random number
generator
...
If you want a different distribution or a better
random number generator, you can supply one
...
For example, for a call r(e−b) the generator must return a value in the range [0,e−b)
...
begin(),dc
...

}

The partition algorithm separates a sequence into two parts based on a partition criterion:
partition()
p=partition(b,e,f)
p=stable_partition(b,e,f)

pair(p1,p2)=partition_copy(b,e,out1,out2,f)

p=partition_point(b,e,f)
is_partitioned(b,e,f)

(§iso
...
3
...
5
...

x

Permutations (§iso
...
4
...
25
...
12)
is true if the next_∗ operation succeeded, otherwise false

x=next_permutation(b,e)
x=next_permutation(b,e,f)
x=prev_permutation(b,e)
x=prev_permutation(b,e,f)
is_permutation(b,e,b2)
is_permutation(b,e,b2,f)

Make [b:e) the next permutation in lexicographical order
Make [b:e) the next permutation, using f for comparison
Make [b:e) the previous permutation in lexicographical order
Make [b:e) the previous permutation, using f for comparison
Is there a permutation of [b2:b2+(e−b)) that compares equal
to [b,e)?
Is there a permutation of [b2:b2+(e−b)) that compares equal
to [b,e), using f(∗p,∗q) as the element comparison?

Permutations are used to generate combinations of elements of a sequence
...


Section 32
...
5

Permutations

941

The next_permutation() takes a sequence [b:e) and transforms it into the next permutation
...

If such a permutation exists, next_permutation() returns true; otherwise, it transforms the sequence
into the smallest permutation, that is, the ascendingly sorted one (abc in the example), and returns
false
...
begin(),v
...


32
...
6 fill()
The fill() family of algorithms provide ways of assigning to and initializing elements of a sequence:
The fill Family (§iso
...
3
...
25
...
7, §iso
...
6
...
For example, using the random number generators Randint and Urand from §40
...
7)

// output 200 random integers in the interval [0:100):
generate_n(ostream_iterator{cout},200,Urand{100});
fill_n(back_inserter{v3},20,99);

// see §40
...
If you need to manipulate raw

942

STL Algorithms

Chapter 32

storage, say, to turn a region of memory into objects of well-defined type and state, you use one of
the uninitialized_ versions (presented in )
...
Elements that are targets of uninitialized_fill() or uninitialized_copy() must be of built-in type or uninitialized
...
begin(),vs
...
begin());
// OK
uninitialized_copy(vs
...
end(),vs2
...
6
...
5
...
25
...
3)
swap(x,y)
p=swap_ranges(b,e,b2)
iter_swap(p,q)

Exchange the values of x and y
swap(v,v2) corresponding elements
swap(∗p,∗q)

in [b:e) and [b2,b2+(e−b))

for example:
void use(vector& v, int∗ p)
{
swap_ranges(v
...
end(),p);
}

// exchange values

The pointer p had better point to an array with at least v
...

The swap() algorithm is possibly the simplest and arguably the most crucial algorithm in the
standard library
...
Its implementation is used as an example in §7
...
2 and the standard-library version is presented in §35
...
2
...
6 Sorting and Searching
Sorting and searching in sorted sequences are fundamental, and the needs of programmers are quite
varied
...

The sort Family (§iso
...
4
...
6

Sorting and Searching

943

The sort Family (continued)(§iso
...
4
...
1
...

Despite its name, is_sorted_until() returns an iterator, rather than a bool
...
3) does not provide random-access iterators, so lists should be sorted
using the specific list operations (§31
...
2) or by copying their elements into a vector, sorting that
vector, and then copying the elements back into the list:
template
void sort_list(List& lst)
{
vector v {lst
...
end()};
sort(v);
copy(v,lst);
}

// initialize from lst
// use container sort (§32
...
If a stable sort is required, stable_sort() should be
used, that is, an N∗log(N)∗log(N) algorithm that improves toward N∗log(N) when the system has sufficient extra memory
...
6)
...

Sometimes, only the first elements of a sorted sequence are needed
...
The

944

STL Algorithms

Chapter 32

plain

partial_sort(b,m,e) algorithms put the elements
tial_sort_copy() algorithms produce N elements, where N

in the range [b:m) in order
...
We need to specify both the
start and the end of the result sequence because that’s what determines how many elements we need
to sort
...
begin(),sales
...
begin(),bestsellers
...
copies_sold()>b2
...
begin(),bestsellers
...

If the number of elements desired to be sorted by a partial_sort() is small compared to the total
number of elements, these algorithms can be significatly faster than a complete sort()
...

The nth_element() algorithm sorts only as far as is necessary to get the Nth element to its proper
place with no element comparing less than the Nth element placed after it in the sequence
...
push_back(randint(1000));
// §40
...
begin(), v
...
end());
cout << "nth: " << v[n] < '\n';
for (int i=0; icout << v[i] << ' ';

This produces:
nth: 24
10 8 15 19 21 15 8 7 6 17 21 2 18 8 1 9 3 21 20 18 10 7 3 3 8 11 11 22 22 23

The nth_element() differs from partial_sort() in that the elements before n are not necessarily sorted,
just all less than the nth element
...

Sorting C-style strings requires an explicit sorting criterion
...
For example:

Section 32
...
However, to sort C-style
strings by string value rather than by address we need a proper sort predicate
...
4
...
To simplify the user interface, the
standard library uses !(x||y ...
2
...


32
...
1 Binary Search
The binary_search() family of algorithms provide binary searches of ordered (sorted) sequences:
Binary Search (§iso
...
4
...
4) is terribly inefficient for large sequences, but it is about
the best we can do without sorting or hashing (§31
...
3
...
Once a sequence is sorted, however, we
can use a binary search to determine whether a value is in a sequence
...
begin(),c
...

}
//
...
As with find(), we often also
want to know where the elements with that value are in that sequence
...
Consequently, algorithms are provided for finding a range of equal elements, equal_range(),
and algorithms for finding the lower_bound() and upper_bound() of that range
...
4
...
We can think of lower_bound() as a fast find()
and find_if() for sorted sequences
...
begin(),c
...
begin(),c
...

}

// probably slow: O(N); c needn’t be sorted
// probably fast: O(log(N)); c must be sorted

If lower_bound(first,last,k) doesn’t find k, it returns an iterator to the first element with a key greater
than k, or last if no such greater element exists
...
This means that we can use these algorithms to determine where
to insert a new element into a sorted sequence so that the sequence remains sorted: just insert
before the second of the returned pair
...


32
...
2 merge()
The merge algorithms combine two ordered (sorted) sequences into one:
The merge Family (§iso
...
4
...
For
example:

Section 32
...
2

merge()

vector v {3,1,4,2};
list lst {0
...
5,2,2
...
begin(),v
...
begin(),v
...
begin(),lst
...
2
...
The output is:
0
...
5, 2, 2, 2
...
6
...
The
input sequences are supposed to be sorted and the output sequences are also sorted
...
25
...
5)
includes(b,e,b2,e2)
includes(b,e,b2,e2,f)
p=set_union(b,e,b2,e2,out)
p=set_union(b,e,b2,e2,out,f)

p=set_intersection(b,e,b2,e2,out)
p=set_intersection(b,e,b2,e2,out,f)

p=set_difference(b,e,b2,e2,out)
p=set_difference(b,e,b2,e2,out,f)

p=set_symmetric_difference(b,e,b2,e2,out)

p=set_symmetric_difference(b,e,b2,e2,out,f)

For example:

Are all elements of [b:e) also in [b2:e2)?
Are all elements of [b:e) also in [b2:e2),
using f for comparison?
Construct a sorted sequence [out:p)
of elements that are in either [b:e) or [b2:e2)
Construct a sorted sequence [out:p)
of elements that are in either [b:e) or [b2:e2),
using f for comparison
Construct a sorted sequence [out:p)
of elements that are in both [b:e) and [b2:e2)
Construct a sorted sequence [out:p)
of elements that are in both [b:e) and [b2:e2),
using f for comparison
Construct a sorted sequence [out:p)
of elements that are in [b:e) but not in [b2:e2)
Construct a sorted sequence [out:p)
of elements that are in [b:e) but not in [b2:e2),
using f for comparison
Construct a sorted sequence [out:p)
of elements that are in [b:e) or [b2:e2)
but not in both
Construct a sorted sequence [out:p)
of elements that are in [b:e) or [b2:e2)
but not in both, using f for comparison

948

STL Algorithms

Chapter 32

string s1 = "qwertyasdfgzxcvb";
string s2 = "poiuyasdfg/
...
begin(),s1
...
begin(),s2
...
size()+s2
...
begin(),s1
...
begin(),s2
...
begin());
cout << s3 << '\n';
for (auto p = s3
...
assign(s1
...
size(),'+');
up = set_difference(s1
...
end(),s2
...
end(),s3
...
begin(); p!=up; ++p)
cout << ∗p;
cout << '\n';

This little test produces:
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
,
...
6
...
Think of a
heap as a representation of a binary tree
...
25
...
6)
make_heap(b,e)
make_heap(b,e,f)
push_heap(b,e)
push_heap(b,e,f)
pop_heap(b,e)
pop_heap(b,e,f)
sort_heap(b,e)
sort_heap(b,e,f)
is_heap(b,e)
is_heap(b,e,f)
p=is_heap_until(b,e)
p=is_heap_until(b,e,f)

Make [b:e) ready to be used as a heap
Make [b:e) ready to be used as a heap, using f for comparison
Add ∗(e−1) to the heap [b:e−1); afterward [b:e) is a heap
Add an element to the heap [b:e−1), using f for comparison
Remove ∗(e−1) from the heap [b:e); afterward, [b:e−1) is a heap
Remove element from the heap [b:e), using f for comparison
Sort the heap [b:e)
Sort the heap [b:e), using f for comparison
Is [b:e) a heap?
Is [b:e) a heap, using f for comparison?
p is the largest p such that [b:p) is a heap
p is the largest p such that [b:p) is a heap, using f for comparison

Section 32
...
4

Heaps

949

Think of the end, e, of a heap [b:e) as a pointer, which it decremented by pop_heap() and incremented by push_heap()
...
g
...
A new element is inserted by writing through e (e
...
, ∗e=x) and then doing a
push_heap()
...
begin(),s
...
begin(),s
...
begin(),s
...
begin(),s
...
end()−3)='f';
push_heap(s
...
end()−2);
∗(s
...
begin(),s
...
end()−1)='y';
push_heap(s
...
end());
sort_heap(s
...
end());
reverse(s
...
end());

// rogheeew
// rogheeew
// ohgeeerw
// hegeeorw

// hegeefrw
// xeheefge
// yxheefge
// eeefghxy
// yxhgfeee

The way to understand the changes to s is that a user reads only s[0] and writes only s[x] where x is
the index of the current end of the heap
...

The point of a heap is to provide fast addition of elements and fast access to the element with
the highest value
...


32
...
5 lexicographical_compare()
A lexicographical compare is the rule we use to order words in dictionaries
...
25
...
8)
lexicographical_compare(b,e,b2,e2)
lexicographical_compare(b,e,b2,e2,f)

Is [b:e)<[b2:e2)?
Is [b:e)<[b2:e2), using f for element comparison?

We might implement lexicographical_compare(b,e,b2,e2) like this:
template
bool lexicographical_compare(In first, In last, In2 first2, In2 last2)
{
for (; first!=last && first2!=last2; ++first,++last) {
if (∗first<∗first2)
return true;
// [first:last)<[first2:last2)
if (∗first2<∗first)
return false; // [first2:last2)<[first:last)
}
return first==last && first2!=last2; // [first:last)<[first2:last2) if [first:last) is shorter
}

That is, a string compares as a sequence of characters
...
begin(),n1
...
begin(),n2
...
begin(),n1
...
begin(),n2
...
7 Min and Max
Value comparisons are useful in many contexts:
The min and max Family (§iso
...
4
...

Unfortunately, the versions that take lvalues take const lvalues, so you can never modify the result
of one of these functions
...
7

++min(x,y);
++min({x,y});

Min and Max

951

// the result of min(x,y) is a const int&
// error: the result of min({x,y}) is an rvalue (an initializer_list is immutable)

The _element functions return iterators and the minmax function returns pairs, so we can write:
string s = "Large_Hadron_Collider";
auto p = minmax_element(s
...
end(),
[](char c1,char c2) { return toupper(c1)cout << "min==" << ∗(p
...
second) << '\n';

With the ACSII character set on my machine, this little test produces:
min==a max==_

32
...
2
...
2
...
2
...
2
...
2
...
2
...
2
...
3
...
3
...
3
...
3
...

Use for_each() and transform() only when there is no more-specific algorithm for a task;
§32
...
1
...
5
...
5
...

If you have to deal with uninitialized objects, consider the uninitialized_∗ algorithms; §32
...
6
...
6
...
6
...

– Alex Stepanov









Introduction
Iterator Model
Iterator Categories; Iterator Traits; Iterator Operations
Iterator Adaptors
Reverse Iterators; Insert Iterators; Move Iterator
Range Access Functions
Function Objects
Function Adaptors
bind(); mem_fn(); function
Advice

33
...
The
STL consists of the iterator, container, algorithm, and function object parts of the standard library
...

Iterators are the glue that ties standard-library algorithms to their data
...


my_algo()

your_fct()

Iterators

vector

map

list


...
1
...
g
...
g
...
A
sequence is defined by a pair of iterators defining a half-open range [begin:end):
iterators:

begin

end

elements:
That is, begin points to the first element of the sequence, and end points to the one-beyond-the-last
element of the sequence
...
Note that the empty sequence has
begin==end; that is, [p:p) is the empty sequence for any iterator p
...

Algorithms that search for something in a sequence usually return the end of the sequence to
indicate ‘‘not found’’; for example:
auto p = find(v
...
end(),x);
if (p!=v
...
begin():v
...
1
...
In that case,
it is the programmer’s responsibility not to write beyond the end of that sequence
...
begin(),v
...
begin(),1000);
}

// OK
// big trouble

Some standard-library implementations range check – that is, throw an exception for that last call
of forward() – but you can’t rely on that for portable code: many implementations don’t check
...
2
...


33
...
2 Iterator Categories
The standard library provides five kinds of iterators (five iterator categories):
• Input iterator: We can iterate forward using ++ and read each element (repeatedly) using ∗
...
This is the kind of iterator that istream
offers; see §38
...

• Output iterator: We can iterate forward using ++ and write an element once only using ∗
...
5
...
If a forward iterator points to a class
object, we can use −> to refer to a member
...
This is the kind of iterator forward_list offers (§31
...

• Bidirectional iterator: We can iterate forward (using ++) and backward (using −−) and read
and write (unless the elements are const) elements repeatedly using ∗
...
We can compare bidirectional iterators using == and !=
...
4)
...
If a
random-access iterator points to a class object, we can use −> to refer to a member
...
We can find the distance between two random-access iterators to the same
sequence by subtracting one from the other
...
This is the kind of iterator that vector offers (§31
...

Logically, these iterators are organized in a hierarchy (§iso
...
2):

956

STL Iterators

Chapter 33

Iterator
∗, ++
Input Iterator
single read, −>

==, !=,

Output Iterator
single write

Forward Iterator
repeated read and write
Bidirectional Iterator
−−

Random-access Iterator
[], +, +=, −, −=, <, <=, >, >=

The iterator categories are concepts (§24
...
If you need to do something advanced with iterator categories, use iterator_traits (directly or indirectly)
...
1
...
24
...
1)
iterator_traits
iterator_traits
iterator
input_iterator_tag
output_iterator_tag
forward_iterator_tag

bidirectional_iterator_tag

random_access_iterator_tag

Traits type for a non-pointer Iter
Traits type for a pointer T∗
Simple class defining the basic iterator member types
Category for input iterators
Category for output iterators
Category for forward iterators;
derived from input_iterator_tag;
provided for forward_list, unordered_set,
unordered_multiset, unordered_map, and unordered_multimap
Category for bidirectional iterators;
derived from forward_iterator_tag;
provided for list, set, multiset, map, multimap
Category for random-access iterators;
derived from bidirectional_iterator_tag;
provided for vector, deque, array, built-in arrays, and string

Section 33
...
3

Iterator Traits

957

The iterator tags are types used to select among algorithms based on the type of an iterator
...
g
...
Variants of this technique are pervasive in the STL
...
g
...
do some checking
...
Calling this read() with a pointer argument would be an error
...
Instead, we
can write:
template
typename iterator_traits::value_type read(Iter p, int n)
{
//
...

return p[n];
{

// more general

The idea is that to find a property of an iterator, you look in its iterator_traits (§28
...
4), rather than
at the iterator itself
...
For example:
template
using Category = typename std::iterator_traits::iterator_category;
template
using Difference_type = typename std::iterator_traits::difference_type;

So, if we want to know the type of the difference between two iterators (pointing to the same
sequence), we have some choices:
tempate
void f(Iter p, Iter q)
{
Iter::difference_type d1 = distance(p,q);

// syntax error: ‘‘typename’’ missing

typename Iter::difference_type d2 = distance(p,q); // doesn’t work for pointers, etc
...


// OK, but ugly
// OK, much better

// OK, if you don’t need to mention the type explicitly

}

I recommend the last two alternatives
...
1
...
1
...
1
...
24
...
2)
++p

p++

∗p
−−p
p−−
p[n]
p−>n
p==q
p!=q
pp<=q
p>q
p>=q
p+=n
p−=n
q=p+n
q=p−n

Pre-increment (advance one element): make p refer to the next element
or to the one-beyond-the-last element;
the resulting value is the incremented value
Post-increment (advance one element): make p refer to the next element
or to the one-beyond-the-last element;
the resulting value is p’s value before the increment
Access (dereference): ∗p refers to the element pointed to by p
Pre-decrement (go back one element): make p point to the previous element;
the resulting value is the decremented value
Post-decrement (go back one element): make p point to the previous element;
the resulting value is p’s value before the decrement
Access (subscripting): p[n] refers to the element pointed to by p+n;
equivalent to ∗(p+n)
Access (member access): equivalent to (∗p)
...
Thus, for
more complicated iterators, ++p is likely to be more efficient than p++
...
1
...
24
...
4)
advance(p)
x=distance(p,q)
q=next(p,n)
q=next(p)
q=prev(p,n)
q=prev(p)

Like p+=n; p must be at least an input iterator
Like x=q−p; p must be at least an input iterator
Like q=p+n; p must be at least a forward iterator
q=next(p,1)

Like q=p−n; p must be at least a bidirectional iterator
q=prev(p,1)

In each case, if p is not a random-access iterator, the algorithm will take n steps
...
2 Iterator Adaptors
In , the standard library provides adaptors to generate useful related iterator types from a
given iterator type:
Iterator Adaptors
reverse_iterator
back_insert_iterator
front_insert_iterator
insert_iterator
move_iterator
raw_storage_iterator

Iterate backward
Insert at end
Insert at beginning
Insert anywhere
Move rather than copy
Write to uninitialized storage

§33
...
1
§33
...
2
§33
...
2
§33
...
2
§33
...
3
§34
...
2
...
5
...
2
...
If the sequence allows bidirectional
access, we can also traverse the sequence in reverse order, from e to b
...
A reverse_iterator iterates from the end of the sequence defined by its
underlying iterator to the beginning of that sequence
...
Thus, the fundamental
relation between a reverse iterator and its corresponding iterator is &∗(reverse_iterator(p))==&∗(p−1)
...
rbegin() points to its last element, v[v
...
Consider:
begin()

end()

A

B

C

This sequence can be viewed like this using a reverse_iterator:

Section 33
...
1

Reverse Iterator

rbegin()

961

rend()

C

B

A

The definition of reverse_iterator looks something like this:
template
class reverse_iterator
: public iterator,
Value_type,
Difference_type,
Pointer,
Reference> {
public:
using iterator_type = Iter;
reverse_iterator(): current{} { }
explicit reverse_iterator(Iter p): current{p} { }
template
reverse_iterator(const reverse_iterator& p) :current(p
...

protected:
Iterator current;
// current points to the element after the one *this refers to
private:
//
...
In particular, if
random-access operator, its reverse_iterator has [], +, and <
...
rbegin()[3] = 7;
// OK: random-access iterator
lst
...
rbegin(),3)) = '4';
// OK!
}

I use next() to move the iterator because (like []) + wouldn’t work for a bidirectional iterator, such as
list::iterator
...

For example, to find the last occurrence of an element in a sequence, we can apply find() to its
reverse sequence:
auto ri = find(v
...
rend(),val);

// last occurrence

Note that C::reverse_iterator is not the same type as C::iterator
...
begin())
{
auto ri = find(c
...
rend(),v);
if (ri == c
...
end();
return prev(ri
...
end() to indicate "not found"

For a reverse_iterator, ri
...

So, to get an iterator pointing to the same element as the reverse iterator ri, I have to return
ri
...
However, my container may be a list that does not support − for its iterators, so I use
prev() instead
...
begin())
{
for (auto p = c
...
rend(); ++p)
if (∗p==v) return −−p
...
end();
}

// view sequence in reverse order
// use c
...
begin())
{
for (auto p = c
...
begin(); )
// search backward from end
if (∗−−p==v) return p;
return c
...
end() to indicate "not found"
}

As for the earlier definitions of find_last(), this version requires at least a bidirectional iterator
...
2
...
2
...
This implies the possibility of overflow and consequent memory corruption
...
begin(),200,7);
}

// assign 7 to vi[0]
...

In , the standard library provides a solution in the form of an inserter: when written to,
an inserter inserts a new element into a sequence rather than overwriting an existing element
...
So, a container grows by one element each time a value is written
to it through an insert iterator
...

There are three insert iterators:
• insert_iterator inserts before the element pointed to using insert()
...

• back_insert_iterator inserts after the last element of the sequence using push_back()
...
24
...
2)
ii=inserter(c,p)
ii=back_inserter(c)
ii=front_inserter(c)

ii
ii
ii

is an insert_iterator pointing to p in container c
is a back_insert_iterator pointing to back() in container c
is a front_insert_iterator pointing to front() in container c

The iterator passed to inserter() must be an iterator into the container
...
For example, you
can’t use inserter() to make an iterator to insert into a forward_list
...
g
...

An inserter is an output iterator:
insert_iterator
insert_iterator p {c,q};
insert_iterator p {q};
p=q
p=move(q)

Operations (§iso
...
5
...
24
...
2)

Make p point to the next element; the value is p’s new value
Make p point to the next element; the value is p’s old value
Insert x before p
Insert x before p, then increment p

The front_insert_iterator and
iterator
...


33
...
3 Move Iterator
A move iterator is an iterator where reading from the pointed-to element moves rather than copies
...
For example, we can
do −−p if the move iterator p was made from a bidirectional iterator
...
7
...
For example:
vector read_strings(istream&);
auto vs = read_strings(cin);

// get some strings

vector vs2;
copy(vs,back_inserter(vs2));

// copy strings from vs into vs2

vector vs3;
copy(vs2,make_move_iterator(back_inserter(vs3)));

// move strings from vs2 into vs3

This assumes that a container version of std::copy() has been defined
...
3 Range Access Functions
In , the standard library provides a nonmember begin() and end() functions for containers:
begin()
p=begin(c)
p=end(c)

p
p

and end() (§iso
...
6
...
begin()
is an iterator for the one-past-the-end of c; c is a built-in array or has c
...
3

Range Access Functions

965

template
auto begin(C& c) −> decltype(c
...
begin());
template
auto end(C& c) −> decltype(c
...
end());
template
auto begin(T (&array)[N]) −> T∗;
template
auto end(T (&array)[N]) −> T∗;

// for built-in arrays

These functions are used by the range-for-statement (§9
...
1) but can of course also be used directly
by users
...
begin() and c
...

A user-defined container with member begin() and end() automatically gets nonmember versions
when is #included
...
size()};
}

// iterator to first element

// iterator to last element

966

STL Iterators

Chapter 33

Here, I assume that passing the address of the first element is a way to create an iterator to the first
element of My_container and that My_container has a size()
...
4 Function Objects
Many of the standard algorithms take function objects (or functions) as arguments to control the
way they work
...
In , the standard library supplies a few common function
objects:
Predicates (§iso
...
8
...
20
...
6, §iso
...
8
...

sort(v
...
end(),greater{});

// sor t v into decreasing order

Such predicates are roughly equivalent to simple lambdas
...

sort(v
...
end(),[](int a, int b) { return a>b; });

// sor t v into decreasing order

Note that logical_and and logical_or always evaluate both their arguments (&& and || do not)
...
20
...
4)
f=plus(x,y)
f=minus(x,y)
f=multiplies(x,y)
f=divides(x,y)
f=modulus(x,y)
f=negate(x)

f(x,y) means x+y when x and y are of type T
f(x,y) means x−y when x and y are of type T
f(x,y) means x∗y when x and y are of type T
f(x,y) means x/y when x and y are of type T
f(x,y) means x%y when x and y are of type T
f(x) means −x when x is of type T

Section 33
...
5 Function Adaptors
A function adaptor takes a function as argument and returns a function object that can be used to
invoke the original function
...
20
...
9, §iso
...
8
...
20
...
8)
g=bind(f,args)

g=mem_fn(f)
g=not1(f)
g=not2(f)

g(args2) is equivalent to f(args3) where args3 is obtained
by replacing placeholders in args with arguments from args2
for the use of placeholders, such as _1, _2, and _3
g(p,args) means p−>f(args) if p is a pointer and p
...

These binders, and their deprecated predecessors (such as bind1st(), mem_fun(), and mem_fun_ref()),
were heavily used in the past, but most uses seem to be more easily expressed using lambdas
(§11
...


33
...
1 bind()
Given a function and a set of arguments, bind() produces a function object that can be called with
‘‘the remaining’’ arguments, if any, of the function
...
For example:

cube(2)
...
In this case, g()’s (first) argument is used as f()’s second argument
...

The placeholder mechanism is very flexible
...
This implies that references are dereferenced before bind() gets to see them
...
20
...
3)

is a reference_wrapper for T& t; noexcept
is a reference_wrapper for a const T& t; noexcept

This solves the ‘‘reference problem’’ for bind():
void user()
{
int i = 1;
incr(i);
auto inc = bind(incr,_1);
inc(ref(i));
}

// i becomes 2
// i becomes 3

This ref() is needed to pass references as arguments to threads because thread constructors are variadic templates (§42
...
2)
...
This saves me the bother of specifying the return type of a call of bind()
...
In particular, the returned function object is larger when it has to hold values of bound
parameters
...
If so, we can specify them for a function (§33
...
3)
...
5
...
5
...
For example:
void user(Shape∗ p)
{
p−>draw();
auto draw = mem_fn(&Shape::draw);
draw(p);
}

The major use of mem_fn() is when an algorithm requires an operation to be called as a nonmember
function
...
begin(),v
...

Often, lambdas provide a simple and general alternative to binders
...
begin(),v
...
5
...
In that, bind() resembles a lambda
...
A function is specified with a specific return type and a specific argument type
...
)>
function f {};
function f {nullptr};
function f {g};
function f {allocator_arg_t,a};
function f {allocator_arg_t,a,nullptr_t};
function f {allocator_arg_t,a,g};
f2=f
f=nullptr

(§iso
...
8
...
2) (continues)

is an empty function; noexcept
is an empty function; noexcept
is a function holding g; g can be anything that
can be invoked with f’s argument types
f is an empty function; use allocator a; noexcept
f is an empty function; use allocator a; noexcept
f is a function holding g; use allocator a; noexcept
f2 is a copy of f
f becomes empty
f
f
f

970

STL Iterators

Chapter 33

function ...
swap(f2)
f
...
target_type()
p=f
...
20
...
11
...
target_type()==typeid(F), p points to the
contained object, otherwise, p==nullptr; noexcept
Is f empty? noexcept
f==nullptr
!(f==nullptr)
!(f==nullptr)
f
...

The standard-library function is a type that can hold any object you can invoke using the call
operator () (§2
...
1, §3
...
3, §11
...
2
...
That is, an object of type function is a function object
...
5)); }

// conventional 4/5 rounding

function f; // f can hold anything that can be called with a double and return an int
enum class Round_style { truncate, round };
struct Round {
// function object carrying a state
Round_style s;
Round(Round_style ss) :s(ss) { }
int operator()(double x) const { return (s==Round_style::round) ? (x+0
...
5
...
6) << '\n';
f = Round(Round_style::truncate);
cout << f(7
...
5 : x; };
cout << f(7
...
6};
f = Round(Round_style::round);
std::transform(v
...
end(),v
...

Obviously, functions are useful for callbacks, for passing operations as arguments, etc
...
6 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]
[14]
[15]
[16]

An input sequence is defined by a pair of iterators; §33
...
1
...
1
...

For any iterator p, [p:p] is the empty sequence; §33
...
1
...
1
...

Think of iterators as more general and often better behaved pointers; §33
...
1
...
1
...

Use iterator_traits to obtain information about iterators; §33
...
3
...
1
...

Use iterator_traits to select an optimal algorithm based on an iterator’s category; §33
...
3
...
1
...

Use base() to extract an iterator from a reverse_iterator; §33
...
1
...
2
...

A move_iterator can be used to make copy operations into move operations; §33
...
3
...
3
...
5
...

Note that bind() dereferences references early; use ref() if you want to delay dereferencing;
§33
...
1
...
5
...

[18] Use function when you need a variable that can hold a variety of callable objects; §33
...
3
...

– Terry Pratchett









Introduction
‘‘Almost Containers’’
array; bitset; vector; Tuples
Resource Management Pointers
unique_ptr; shared_ptr; weak_ptr
Allocators
The Default Allocator; Allocator Traits; Pointer Traits; Scoped Allocators
The Garbage Collection Interface
Uninitialized Memory
Temporary Buffers; raw_storage_iterator
Advice

34
...
This chapter presents facilities
that are more specialized or deal with raw memory (as opposed to typed objects)
...
2 ‘‘Almost Containers’’
The standard library provides several containers that don’t fit perfectly into the STL framework
(§31
...
2, §33
...
Examples are built-in arrays, array, and string
...
4), but that is not quite fair: they hold elements, so they are containers,
but each has restrictions or added facilities that make them awkward in the context of the STL
...

‘‘Almost Containers’’
T[N]
array
bitset
vector
pair
tuple ...
If the standard library didn’t provide them, many people would have to
design and implement their own
...

• array, vector, and tuple elements are contiguously allocated; forward_list and map are linked
structures
...

• basic_string requires its elements to be some form of character and to provide string manipulation, such as concatenation and locale-sensitive operations (Chapter 39) and valarray
requires its elements to be numbers and to provide numerical operations
...
No single container could serve all of these needs because some needs are contradictory, for example, ‘‘ability to grow’’ vs
...
‘‘contiguously allocated
...


34
...
1 array
An array, defined in , is a fixed-size sequence of elements of a given type where the number
of elements is specified at compile time
...
The elements are allocated in the scope where the array is
defined
...
There is no overhead (time or space) involved in using an array compared to using a
built-in array
...

Instead, an array directly contains its elements:

Section 34
...
1

array

975

template
// an array of N Ts (§iso
...
3
...
4),
except operations that change the container size, constructors, and assign() functions
*/
void fill(const T& v);// assign N copies of v
void swap(array&) noexcept(noexcept(swap(declval(), declval())));
T __elem[N];

// implementation detail

};

No ‘‘management information’’ (e
...
, a size) is stored in an array
...
5)
an array is no more efficient than copying it (unless the array’s elements are resource handles with
efficient moves)
...

The number of elements and subscript values for array are of an unsigned type (size_t), just like
vector’s, but different from the built-in array’s
...
Hope for a warning
...
As usual, if the initializer list provides values for some but not all elements,
the remainder is initialized with the appropriate default value
...

The element count is not optional:
array ax = { 1, 2, 3 }; // error size not specified

To save us from a special case, the number of elements can be zero:
int a0;

The element count must be a constant expression:
void f(int n)
{
array aa = {"John's", "Queens' "};
//
}

// error : size not a constant expression

If you need the element count to be variable, use vector
...


array’s

element

976

Memory and Resources

Chapter 34

There is no constructor for array that copies an argument value (as there is for vector; §31
...
2)
...
fill(99);
//
...
The declaration of
array::swap() basically says that if a swap() of Ts can throw, then so can a swap() of an
array
...

When necessary, an array can be explicitly passed to a C-style function that expects a pointer
...
size());
f(&a[0],a
...
data(),a
...
begin(),a
...


// C++/STL-style use

}

Why would we use an array when vector is so much more flexible? Because an array is less flexible, it is simpler
...
On the other hand,
the stack is a limited resource (especially on some embedded systems), and stack overflow is nasty
...
However, my main reason to prefer array is that it saves me from surprising nasty conversions to pointers
...

Shape∗ p1 = a1;
// OK: disaster waiting to happen
Shape∗ p2 = a2;
// error: no conversion of array to Shape*
p1[3]
...
2
...
2
...
5
...
4)
...

An array can be seen as a tuple (§34
...
4) where all elements are of the same type
...
The tuple helper type functions tuple_size and tuple_element
can be applied to arrays:
tuple_size>::value
tuple_element>::type

// N
// T

We can also use a get function to access the ith element:
template
T& get(array& a) noexcept;
template
T&& get(array&& a) noexcept;
template
const T& get(const array& a) noexcept;

For example:
array a = {1,2,3,5,8,13,25};
auto x1 = get<5>(a);
auto x2 = a[5];
auto sz = tuple_size::value;
typename tuple_element<5,decltype(a)>::type x3 = 13;

// 13
// 13
// 7
// x3 is an int

These type functions are for people writing code that expects tuples
...
2
...
2
...


34
...
2 bitset
Aspects of a system, such as the state of an input stream (§38
...
5
...
C++ supports the
notion of small sets of flags efficiently through bitwise operations on integers (§11
...
1)
...
For sets of bits that don’t fit into a long
long int, using a bitset is much more convenient than using integers directly
...
If you want to name the bits, rather than numbering them, the alternatives are
to use a set (§31
...
3), an enumeration (§8
...
2
...

A bitset is an array of N bits
...
A bitset differs from a vector
(§34
...
3) by being of fixed size, from set (§31
...
3) by having its bits indexed by integers rather than
associatively by value, and from both vector and set by providing operations to manipulate
the bits
...
2)
...
This is actually a generally useful technique for
addressing objects for which a built-in pointer for some reason is unsuitable:
bitset

template
class bitset {
public:
class reference {
// reference to a single bit:
friend class bitset;
reference() noexcept;
public:
// suppor t zero-based subscripting in [0:b
...
flip();
};
//
...
For example, if an
index (also known as a bit position) is out of range, an out_of_range exception is thrown
...
Bit positions are numbered from right to left in the same way bits often are in a
word, so the value of b[i] is pow(2,i)
...
2
...
1 Constructors
A bitset can be constructed with a specified number of zeros, from the bits in an unsigned long long
int, or from a string:
bitset

Constructors (§iso
...
5
...
2
...
1

Constructors

bitset
bitset bs {p,n,z,o};

bitset bs {p,n,z};
bitset bs {p,n};
bitset bs {p};

979

Constructors (continued) (§iso
...
5
...
3)
...
A basic_string (§36
...
For example:
void f()
{
bitset<10> b1; // all 0
bitset<16> b2 = 0xaaaa;
bitset<32> b3 = 0xaaaa;

// 1010101010101010
// 00000000000000001010101010101010

bitset<10> b4 {"1010101010"};
bitset<10> b5 {"10110111011110",4};

// 1010101010
// 0111011110

bitset<10> b6 {string{"1010101010"}};
bitset<10> b7 {string{"10110111011110"},4};
bitset<10> b8 {string{"10110111011110"},2,8};

// 1010101010
// 0111011110
// 0011011101

bitset<10> b9 {string{"n0g00d"}};
bitset<10> b10 = string{"101001"};

// invalid_argument thrown
// error : no implicit string to bitset conversion

}

A key idea in the design of bitset is that an optimized implementation can be provided for
that fit in a single word
...


bitsets

34
...
2
...
test(i)
bs&=bs2
bs|=bs2
bsˆ=bs2

Operations (§iso
...
5) (continues)

The ith bit of bs
The ith bit of bs; throw out_of_range if i is not in [0:bs
...
20
...
set()
bs
...
reset()
bs
...
flip()
bs
...
flip()
Make left-shifted set: bs2=bs, bs2<<=n
Make right-shifted set: bs2=bs, bs2>>=n
Bitwise and: bs3[i]=bs[i]&bs2[i] for each bit in bs
Bitwise or: bs3[i]=bs[i]|bs2[i] for each bit in bs
Bitwise exclusive or: bs3[i]=bs[i]ˆbs2[i] for each bit in bs
Read from is into bs; is is an istream
Write bs to os; os is an ostream

bs[i]=v

Set every bit of bs to 0
b[i]=0;
bs[i]=˜bs[i] for every bit in bs
bs[i]=˜bs[i]

bs3=bs&bs2
bs3=bs|bs2
bs3=bsˆbs2
is>>bs
os<
The >> and << are I/O operators when their first operand is an iostream; othewise, they are shift
operators and their second operand must be an integer
...
That implies that some bits ‘‘fall
off the end’’ and that some positions get the default value 0
...
It does, however, imply that b<<−1 shifts by a
very large positive value, thus leaving every bit of the bitset b with the value 0
...

A bitset also supports common operations such as size(), ==, I/O, etc
...
20
...
to_ulong()
n=bs
...
to_string(c0,c1)
s=bs
...
to_string()

n is the unsigned long corresponding to bs
n is the unsigned long long corresponding to bs
s[i]=(b[i])?c1:c0; s is a basic_string
s=bs
...
template to_string(C{’0’},C{’1’})

Section 34
...
2
...
20
...
count()
n=bs
...
all()
bs
...
none()

n
n

!(bs==bs2)

Do all bits in bs have the value 1?
Does any bit in bs have the value 1?
Does no bit in bs have the value 1?
Specialization of hash for bitset

hash>

The operations to_ullong() and to_string() provide the inverse operations to the constructors
...
If the
value of the bitset has so many significant bits that it cannot be represented as an unsigned long,
to_ulong() throws overflow_error; so does to_ullong() if its bitset argument doesn’t fit
...
For
example, we could write out the binary representation of an int:
void binary(int i)
{
bitset<8∗sizeof(int)> b = i;

// assume 8-bit byte (see also §40
...
to_string,allocator>() << '\n'; // general and verbose
cout << b
...
to_string<>() << '\n';
// use all defaults
cout << b
...
2)

34
...
3 vector
The vector from
bits (bools):



is a specialization of

vector

(§31
...
4)
public:
using const_reference = bool;
using value_type = bool;
// like vector
class reference {
// suppor t zero-based subscripting in [0:v
...

};

The similarity to bitset is obvious, but, unlike bitset but like vector, vector has an allocator
and can have its size changed
...
Also, there is no direct support for converting
integers and strings to and from a vector
...
Also, it is impossible in C++ to
completely faithfully mimic the behavior of a (built-in) reference with a proxy, so don’t try to be
subtle about rvalue/lvalue distinctions when using a vector
...
2
...
2
...
1) holds two values
...
2
...

We use pair when it is useful to know (statically) that we have exactly two values
...


Section 34
...
4
...
2
...
1 pair
In , the standard library provides class pair for manipulating pairs of values:
template
struct pair {
using first_type = T;
// the type of the first element
using second_type = U; // the type of the second element
T first;
U second;

// first element
// second element

//
...
˜pair()
p2=p
p2=move{p}
p
...
20
...
2)

Default constructor: pair p {T{},U{}}; constexpr
p
...
second is initialized to y
Construct from the pair p2: pair p {p2
...
second};
p
...
second is constructed from the elements of tuple t2
Destructor: destroy t
...
second
Copy assignment: p2
...
first and p2
...
second
Move assignment:
p2
...
first) and p2
...
second)
Exchange the values of p and p2

An operation on pair is noexcept if the corresponding operations on its elements are
...

The elements first and second are members that we can directly read and write
...
first;
// print "Cambridge"
p
...

}

The piecewise_construct is the name of an object of type piecewise_construct_t used to distinguish
between constructing a pair with members of tuple types and constructing a pair using tuples as
argument lists for its first and second
...
S
...
second is t2,
bridge",2,"unknown"}
...


pair

// pair of tuples
// pair of Univs

To contrast,

p2
...
20
...
3, §iso
...
3
...
first==p2
...
second==p2
...
first ...
first ...
second ...
swap(p2)
p is a pair holding the value x,y;
if possible, move rather than copy x and y

tuple_size::value
tuple_element::type

The size of a pair of type T
The type of first (if N==0) or second (if N==1)
A reference to the Nth element of the pair p; N must be 0 or 1

get(p)

The make_pair function avoids explicit mention of the element types of a pair
...
2
...
2 tuple
In , the standard library provides class
sequence of N elements of arbitrary types:

tuple

and various supporting facilities
...
Types>
class tuple {
public:
//
...

For details of tuple design, implementation, and use, see §28
...
6
...

tuple ...
20
...
2) (continues)

Default constructor: the empty tuple; constexpr
t has one element for each element of args; explicit
Construct from tuple t2
Construct from pair p

tuple

is a

Section 34
...
4
...
>
tuple t {allocator_arg_t,a,args};
tuple t {allocator_arg_t,a,t2};
tuple t {allocator_arg_t,a,p};
t
...
swap(t2)

985

Members (continued) (§iso
...
4
...
, are not required to be the same
...
For example, we
can assign one tuple to another if each element of the assigned tuple can be assigned to the target
element
...
Similarly, a tuple operation is constexpr if the element operations are
...

Note that the general tuple constructor is explicit
...
get<2>(),t
...
get<1>()}; // error : explicit tuple constructor
}
auto t2 = rotate({3,7,9}); // error: explicit tuple constructor

If all you need is two elements, you can use pair:
pair rotate(pair p)
{
return {p
...
first};
}
auto p2 = rotate({3,7});

For more examples, see §28
...
4
...
>

Helpers (§iso
...
4
...
4, §iso
...
4
...
9) (continues)

t=make_tuple(args)
t=forward_as_tuple(args)
t=tie(args)

Make tuple from args
t is a tuple of rvalue references to the elements in args
so you can forward the elements of arg through t
t is a tuple of lvalue references to the elements of args
so you can assign to the elements of args through t

986

Memory and Resources

tuple ...
20
...
2
...
20
...
2
...
swap(t2)

For example, tie() can be used to extract elements from a tuple:
auto t = make_tuple(2
...
Thus, an ignore in a
implies that attempts to assign to its tuple position are ignored
...
For example:

tuple

came from ‘‘elsewhere’’ so that we didn’t

tuple compute();
//
...
3 Resource Management Pointers
A pointer points to an object (or not)
...
That is, looking just at a pointer, we have no idea who is supposed to delete the object
pointed to, or how, or if at all
...
3
...
3
...
3
...
2
...


Section 34
...
1

unique_ptr

987

34
...
1 unique_ptr
The unique_ptr (defined in ) provides a semantics of strict ownership:
• A unique_ptr owns the object to which it holds a pointer
...

• A unique_ptr cannot be copied (has no copy constructor or copy assignment)
...

• A unique_ptr stores a pointer and deletes the object pointed to (if any) using the associated
deleter (if any) when it is itself destroyed (such as when a thread of control leaves the
unique_ptr’s scope; §17
...
2)
...
2
...
3)
• Passing ownership of dynamically allocated memory to a function
• Returning dynamically allocated memory from a function
• Storing pointers in containers
Think of unique_ptr as being represented by a simple pointer (‘‘the contained pointer’’) or (if it has
a deleter) as a pair of pointers:
up1:

unique_ptr

object

up2:

unique_ptr

object

deleter

When a unique_ptr is destroyed, its deleter is called to destroy the owned object
...
For example:
• A deleter for a local variable should do nothing
...

• The default (‘‘no deleter’’) version of unique_ptr uses delete
...
It can be a specialization or rely on the empty-base optimization (§28
...

This way unique_ptr supports general resource management (§5
...

template>
class unique_ptr {
public:
using pointer = ptr; // type of the contained pointer;
// ptr is D::pointer if that is defined, otherwise T*
using element_type = T;
using deleter_type = D;
//
...


988

Memory and Resources

Chapter 34

unique_ptr (§iso
...
7
...
2)
cp is the contained pointer
unique_ptr up {}
unique_ptr up {p}
unique_ptr up {p,del}
unique_ptr up {up2}
up
...
get()
del=up
...
release()
up
...
reset()
up
...
p=up2
...
p=nullptr; noexcept
Destructor: if cp!=nullptr invoke cp’s deleter
Move assigment: up
...
cp); up2
...
reset(nullptr); that is, delete up’s old object, if any
Conversion to bool: up
...
cp; for contained non-arrays only
x=up
...
cp[n]; for contained arrays only
x=up
...
cp; up
...
cp!=nullptr call deleter for up
...
cp=p
up
...
cp
Exchange up and up2’s values; noexcept
up
...
cp
up
...
cp
!(up==up2)
up2!(up2>up)
!(up2up
...
Had it done so, the meaning of ‘‘ownership’’ would have been very hard to define and/or use
...
3
...

It is possible to have a unique_ptr for a built-in array
...
3
...
20
...
1
...
like the unique_ptr for individual objects, but with [] instead of * and ->
...
5
...
4), a Derived[] is not accepted as an argument to a unique_ptr even
if Base is a public base of Derived
...

};
class Circle : public Base {
//
...
Consider a simple technical example:
unique_ptr f(unique_ptr p)
{
++∗p;
return p;
}
void f2(const unique_ptr& p)
{
++∗p;
}
void use()
{
unique_ptr p {new int{7}};
p=f(p);
// error : no copy constructor
p=f(move(p));
// transfer ownership there and back
f2(p);
// pass a reference
}

The f2() body is slightly shorter than f() and f2() is simpler to call, but I find f() easier to think about
...
See also the discussion of the use of non-const references in §7
...
1
...

It is a fair estimate that the call of f2() is one or two machine instructions faster than a call of f()
(because of the need to place a nullptr in the original unique_ptr), but that is unlikely to be

990

Memory and Resources

Chapter 34

significant
...
This, too, is unlikely to be significant in most programs, so the choice between the
styles of f() and f2() has to be made on reasoning about code quality
...
5):
extern "C" char∗ get_data(const char∗ data); // get data from C program fragment
using PtoCF = void(∗)(void∗);
void test()
{
unique_ptr p {get_data("my_data"),free};
//
...

} // implicit free(p)

Currently, there is no standard-library make_unique() similar to
make_shared() (§34
...
2)
...
Args>
unique_ptr make_unique(Args&&
...
}};
}

make_pair()

(§34
...
4
...
3
...
It is used where two pieces of code need access to some
data but neither has exclusive ownership (in the sense of being responsible for destroying the
object)
...
Think of a shared pointer as a structure with two pointers: one to the object
and one to the use count:
sp1:

sp2:

use count
deleter

object

The deleter is what is used to delete the shared object when the use count goes to zero
...

For example, consider a Node in a general graph used by an algorithm that adds and removes
both nodes and connections between nodes (edges)
...
We could try:

Section 34
...
2

shared_ptr

991

struct Node {
vector edges;
//
...
We could plug in a garbage collector (§34
...
Worse, if the container contained non-memory resources, such as thread handles,
file handles, locks, etc
...

Instead, we can use a shared_ptr:
struct Node {
vector> edges;
thread worker;
//
...
That is,
the destructor for each edges[i] is invoked, and the Node pointed to (if any) is deleted if edges[i] was
the last pointer to it
...
If you have been using counted pointers as
return values from factory functions (§21
...
4) and the like, consider upgrading to unique_ptr rather
than shared_ptr
...
You need some logical
complication to break the circle, for example, use a weak_ptr (§34
...
3)
...

• Shared pointers in a multi-threaded environment can be expensive (because of the need to
prevent data races on the use count)
...
For example, which locks are set at the time of the destructor’s execution?
Which files are open? In general, which objects are ‘‘live’’ and in appropriate states at the
(unpredictable) point of execution?
• If a single (last) node keeps a large data structure alive, the cascade of destructor calls triggered by its deletion can cause a significant ‘‘garbage collection delay
...

A shared_ptr represents shared ownership and can be very useful, even essential, but shared ownership isn’t my ideal, and it always carries a cost (independently of how you represent the sharing)
...
When there
is a choice:

992

Memory and Resources

Chapter 34

• Prefer unique_ptr to shared_ptr
...

The shared_ptr provides a fairly conventional set of operations:
shared_ptr Operations (§iso
...
7
...
2)
cp is the contained pointer; uc is the use count
shared_ptr sp {}
shared_ptr sp {p}
shared_ptr sp {p,del}
shared_ptr sp {p,del,a}
shared_ptr sp {sp2}

sp
...
reset()

sp
...
reset(p,d)
sp
...
get()
x=∗sp
x=sp−>m
n=sp
...
unique()
x=sp
...
swap(sp2)

Default constructor: cp=nullptr; uc=0; noexcept
Constructor: cp=p; uc=1
Constructor: cp=p; uc=1; use deleter del
Constructor: cp=p; uc=1; use deleter del and allocator a
Move and copy constructors:
the move constructor moves and then sets sp2
...
cp=nullptr for the now-shared uc; noexcept
Conversion to bool: sp
...
swap(sp); that is, sp contains pointer{},
and the destruction of the temporary shared_ptr{}
decreases the use count for the old object; noexcept
shared_ptr{p}
...
cp=p; uc==1;
the destruction of the temporary shared_ptr decreases
the use count for the old object
Like sp
...
reset(p) but with the deleter d and the allocator a
p=sp
...
cp; noexcept
x=sp
...
cp==nullptr)
sp
...
cp==nullptr)
x is an ordering function (strict weak order; §31
...
2
...
20
...
2
...
6, §iso
...
7
...
2
...
3
...
20
...
2
...
6, §iso
...
7
...
2
...
cp==sp2
...
cp,sp2
...
swap(sp2)
static_cast for shared pointers:
sp2=shared_ptr(static_cast(sp
...
cp)); noexcept
const_cast for shared pointers:
sp2=shared_ptr(const_cast(sp
...

};
auto p = make_shared(1,"Ankh Morpork",4
...
65}
...


34
...
3 weak_ptr
A weak_ptr refers to an object managed by a shared_ptr
...
A weak_ptr allows access to an object,
owned by someone else, that
• You need access to (only) if it exists
• May get deleted (by someone else) at any time
• Must have its destructor called after its last use (usually to delete a non-memory resource)
In particular, we use weak pointers to break loops in data structures managed using shared_ptrs
...

template
class weak_ptr {
public:
using element_type = T;
//
...
20
...
2
...
˜weak_ptr()
wp=pp
wp
...
reset()
n=wp
...
expired()
sp=wp
...
owner_before(pp)
swap(wp,wp2)

shared_ptr

Default constructor: cp=nullptr; constexpr; noexcept
Copy constructor: cp=pp
...
swap(wp);
pp is a weak_ptr or a shared_ptr; noexcept
Exchange wp’s and wp2’s values; noexcept
Decrease wuc and set wp to nullptr:
weak_ptr{}
...
2
...
1);
pp is a shared_ptr or a weak_ptr
wp
...
’’ All asteroids are owned by ‘‘the game,’’
but each asteroid must keep track of neighboring asteroids and handle collisions
...
Each asteroid must keep a list of other asteroids in its neighborhood
...
On the other hand, an asteroid must not be

Section 34
...
3

weak_ptr

995

destroyed while another asteroid is looking at it (e
...
, to calculate the effect of a collision)
...
What we need is a list of asteroids that might still be intact and a way of ‘‘grabbing onto one’’ for a while
...

vector> va(100);
for (int i=0; i ...
calculate neighbors for new asteroid
...
reset(new Asteroid(weak_ptr(va[neighbor]));
launch(i);
}
//
...
The
key is that we give the Asteroid a weak_ptr to that neighbor
...
The collision
calculation for an Asteroid will look something like this:
void collision(weak_ptr p)
{
if (auto q = p
...
lock returns a shared_ptr to p’s object
//
...

}
else {
// Oops: that Asteroid has already been destroyed
p
...
lock(), it holds a shared_ptr that will not become invalid
...
4 Allocators
The STL containers (§31
...
To do so, they use allocators
...
Thus, the basic allocator functions are:
p=a
...
deallocate(p,n);

For example:

// acquire space for n objects of type T
// release space for n objects of type T pointed to by p

996

Memory and Resources

template
struct Simple_alloc {
using value_type = T;

Chapter 34

// use new[] and delete[] to allocate and deallocate bytes

Simple_alloc() {}
T∗ allocate(size_t n)
{ return reinterpret_cast(new char[n∗sizeof(T)]); }
void deallocate(T∗ p, size_t n)
{ delete[] reinterpret_cast(p); }
//
...
Note the casts to and from
does not invoke constructors and deallocate() does not invoke destructors; they deal
in memory, not typed objects
...
ss-1]
};
template
struct My_alloc {
// use an Arena to allocate and deallocate bytes
Arena& a;
My_alloc(Arena& aa) : a(aa) { }
My_alloc() {}
// usual allocator stuff
};

Once Arenas are made, objects can be constructed in the memory allocated:
constexpr int sz {100000};
Arena my_arena1{new char[sz],sz};
Arena my_arena2{new char[10∗sz],10∗sz};
vector v0;// allocate using default allocator
vector> v1 {My_alloc{my_arena1}};

// construct in my_arena1

vector> v2 {My_alloc{my_arena2}};

// construct in my_arena2

vector> v3;

// construct on free store

Typically, the verbosity would be alleviated by the use of aliases
...
4

Allocators

997

template
using Arena_vec = std::vector>;
template
using Simple_vec = std::vector>;
My_alloc Alloc2 {my_arena2};

// named allocator object

Arena_vec> vcd {{{1,2}, {3,4}}, Alloc2};
Simple_vec vs {"Sam Vimes", "Fred Colon", "Nobby Nobbs"};

// explicit allocator
// default allocator

An allocator imposes space overhead in a container only if its objects actually have state (like
My_alloc)
...
5)
...
4
...


new

and deallocates using

delete

is used (by default) by all

template
class allocator {
public:
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = T∗;
using const_pointer = const T∗;
using reference = T&;
using const_reference = const T&;
using value_type = T;
template
struct rebind { using other = allocator; };
allocator() noexcept;
allocator(const allocator&) noexcept;
template
allocator(const allocator&) noexcept;
˜allocator();
pointer address(reference x) const noexcept;
const_pointer address(const_reference x) const noexcept;
pointer allocate(size_type n, allocator::const_pointer hint = 0);
void deallocate(pointer p, size_type n);
size_type max_size() const noexcept;
template ...
args);

// new(p) U{args}

// allocate n bytes
// deallocate n bytes

998

Memory and Resources

template
void destroy(U∗ p);

Chapter 34

// p->˜U()

};

The curious rebind template is an archaic alias
...
It is provided to allow
an allocator to allocate objects of arbitrary type
...
For example:
template>
class list {
private:
class Link { /*
...


// allocator

// link allocator
// list allocator

};

A more restricted specialization of allocator is provided:
template<>
class allocator {
public:
typedef void∗ pointer;
typedef const void∗ const_pointer;
typedef void value_type;
template struct rebind { typedef allocator other; };
};

This allows us to avoid special cases: We can mention
ence its pointers
...
4
...
A property of an allocator, say, its
pointer type, is found in its trait: allocator_traits::pointer
...

Basically, allocator_traits provide defaults for the usual set of type aliases and allocator functions
...
4
...
4
...
20
...
8
struct allocator_traits {
using allocator_type = A;
using value_type = A::value_type;
using pointer = value_type;
using const_pointer = Pointer_traits::rebind;
using void_pointer = Pointer_traits::rebind;
using const_void_pointer = Pointer_traits::rebind;
using difference_type = Pointer_traits::difference_type;
using size_type = Make_unsigned;
using propagate_on_container_copy_assignment = false_type;
using propagate_on_container_move_assignment = false_type;
using propagate_on_container_swap = false_type;

999

// trick
// trick
// trick
// trick
// trick
// trick
// trick
// trick
// trick

template using rebind_alloc = A;
// trick
template using rebind_traits = Allocator_traits>;
static pointer allocate(A& a, size_type n) { return a
...
allocate(n,hint); }
static void deallocate(A& a, pointer p, size_type n) { a
...
Args>
static void construct(A& a, T∗ p, Args&&
...
); }
template
static void destroy(A& a, T∗ p) { p−>T(); }

// trick
// trick
// trick

// trick

// trick

static size_type max_size(const A& a)
// trick
{ return numeric_limits::max() }
static A select_on_container_copy_construction(const A& rhs) { return a; } // trick
};

The ‘‘trick’’ is to use the equivalent member of the allocator A if it exists; otherwise, the default
specified here
...

The Args are any type arguments needed by A
...
4) allows this to be implemented in C++
...


34
...
3 Pointer Traits
An allocator uses pointer_traits to determine properties of pointers and proxy types for pointers:
template
struct pointer_traits {
using pointer = P;
using element_type = T;
using difference_type = ptrdiff_t;

// §iso
...
6
...
4
...
To use the T, the template argument P
must be the first argument of a Ptr template
...


34
...
4 Scoped Allocators
A rather sneaky problem can occur when using containers and user-defined allocators: Should an
element be in the same allocation area as its container? For example, if you use Your_allocator for
Your_string to allocate its elements and I use My_allocator to allocate elements of My_vector then
which allocator should be used for string elements in My_vector>?
Gorm
Harald
Sven

The solution is the ability to tell a container which allocator to pass to elements
...
InnerA>
class scoped_allocator_adaptor : public OuterA {
private:
using Tr = allocator_traits;
public:
using outer_allocator_type = OuterA;
using inner_allocator_type = see below;

// §iso
...
12
...
4
...
20
...
2 */;
using propagate_on_container_move_assignment = /* see §iso
...
12
...
20
...
2 */;
//
...
A
few more aliases would make that code a bit more readable, but it is good that this is not the kind of
code you have to write every day
...
4
...
inner_allocator()
x=a
...
allocate(n)

(Abbreviated, §iso
...
12
...
allocate(n,hint)

Chapter 34

(continued) (Abbreviated, §iso
...
12
...
deallocate(p,n)
n=a
...
construct(args)
a
...
5 The Garbage Collection Interface
Garbage collection (automatic recycling of unreferenced regions of memory) is sometimes presented as a panacea
...
In particular, resources that are not pure memory can be leaked by a
garbage collector
...
I see garbage collection as
a convenient last resort after the usual techniques for preventing leaks have been exhausted:
[1] Use resource handles with the proper semantics for an application whenever possible
...

Move semantics allow such objects to be efficiently returned from a function
...

[3] Use shared_ptrs to hold objects that require shared ownership
...
e
...
However, in a very large number of real-world
programs these techniques (all based on RAII; §13
...
These ‘‘different
ways’’ often involve complicated pointer uses, naked news and deletes, explicit type conversions
that obscure resource ownership, and similar error-prone low-level techniques
...
It can reclaim/recycle memory, even if it cannot handle non-memory resources
...
A garbage collector can sometimes extend the running
time for leaking systems (even systems that leak non-memory resources) significantly
...
Also, a garbage collector can be instrumented to find the sources of leaks
...
For
example, if we put a pointer to an object into a hash table and forget its key, the object is de facto
leaked
...
g
...
Sometimes,
resources ‘‘living’’ for an excessive time can be as bad for a system as a permanent leak
...
5

The Garbage Collection Interface

1003

From this basic philosophy it follows that garbage collection is optional in C++
...
A garbage collector is not even
a required part of a standard C++ implementation, but good free and commercial collectors are
available
...

The rules for pointers and lifetimes are expressed in terms of safely-derived pointers
(§iso
...
7
...
3)
...
’’ Here are some examples of pointers that are not safely derived, also known as
disguised pointers
...
collector may run here
...
collector may run here
...
collector may run here
...

Don’t use such tricks in a program you want to be considered well behaved and comprehensible
to ordinary mortals – even if you don’t plan to use a garbage collector
...

There are legitimate reasons to disguise pointers (e
...
, the xor trick in exceptionally memoryconstrained applications), but not as many as some programmers think
...
g
...
Such pointers are
called traceable
...
g
...
20
...
4):
void declare_reachable(void∗ p);
template
T∗ undeclare_reachable(T∗ p);

// the object pointed to by p must not be collected
// undo a declare_reachable()

void declare_no_pointers(char∗ p, size_t n);
void undeclare_no_pointers(char∗ p, size_t n);

// p[0:n) holds no pointers
// undo a declare_no_pointers()

C++ garbage collectors have traditionally been conservative collectors; that is, they do not move
objects around in memory and have to assume that every word in memory might contain a pointer
...
For example, we might use declare_no_pointers()
to tell the collector where our photographic images are in an application, so as to allow the collector to ignore potentially gigabytes of non-pointer data
...
3
...
4
...
the effect of using an invalid pointer value (including passing
it to a deallocation function) is undefined
...
Collect every object that does not have a safely derived or traceable pointer to it
...
’’
• strict: Safely-derived and not safely-derived pointers may be treated differently; that is, a
garbage collector may be running and will ignore pointers that’s not safely derived
...
Consider that a quality-of-implementation issue or a programming environment issue
...
6

Uninitialized Memory

1005

34
...
Doing so simplifies programming and
eliminates many kinds of errors
...

In addition to the standard allocator, the header provides the fill∗ family of functions
for dealing with uninitialized memory (§32
...
6)
...
These functions are intended primarily for implementers of containers and algorithms
...
6)
...
6
...
Often, such temporary space is
best allocated in one operation but not initialized until a particular location is actually needed
...
If it
succeeds in allocating some memory, it returns a pointer to the first uninitialized space and the
number of objects of type X that will fit into that space; otherwise, the second value of the pair is
zero
...
It may also yield less, however, so one
way of using get_temporary_buffer() is to optimistically ask for a lot and then use what happens to
be available
...
Just as get_temporary_buffer() allocates without constructing, return_temporary_buffer() frees without destroying
...


34
...
2 raw_storage_iterator
The standard algorithms that write into a sequence assume that the elements of that sequence have
been previously initialized
...
Consequently, we cannot use uninitialized memory as the immediate target of an algorithm
...
The solution is to use a
raw_storage_iterator from that initializes instead of assigns:

1006

Memory and Resources

Chapter 34

template
class raw_storage_iterator : public iterator {
Out p;
public:
explicit raw_storage_iterator(Out pp) : p{pp} { }
raw_storage_iterator& operator∗() { return ∗this; }
raw_storage_iterator& operator=(const T& val)
{
new(&∗p) T{val};
// place val in *p (§11
...
4)
return ∗this;
}
raw_storage_iterator& operator++() {++p; return ∗this; }
raw_storage_iterator operator++(int)
{
auto t = ∗this;
++p;
return t;
}

// pre-increment
// post-increment

};

A raw_storage_iterator should never be used to write to initialized data
...
Consider generating a set of permutations (§32
...
5) of strings for use in testing:
void test1()
{
auto pp = get_temporary_buffer(1000);
// get uninitialized space
if (pp
...
handle allocation failure
...
first); // the iterator
generate_n(p,a
...

return_temporary_buffer(p);
}

This is a somewhat contrived example because I see nothing wrong in allocating default initialized
storage for the strings and then assigning the test strings
...
2, §13
...

Note that there are no == or != operators for raw_storage_iterator, so don’t try to use it to write to
a [b:e) range
...
6) will not work if b and e are raw_storage_iterators
...


Section 34
...
7 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]
[12]
[13]
[14]
[15]
[16]
[17]
[18]
[19]

Use array where you need a sequence with a constexpr size; §34
...
1
...
2
...

Use bitset if you need N bits and N is not necessarily the number of bits in a built-in integer
type; §34
...
2
...
2
...

When using pair, consider make_pair() for type deduction; §34
...
4
...

When using tuple, consider make_tuple() for type deduction; §34
...
4
...

Use unique_ptr to represent exclusive ownership; §34
...
1
...
3
...

Minimize the use of weak_ptrs; §34
...
3
...
4
...
5
...
5
...
5
...
5
...
5
...
5
...
5
...
5
...
6
...

– Bertrand Russell








Introduction
Time
duration; time_point; Clocks; Time Traits
Compile-Time Rational Arithmetic
Type Functions
Type Traits; Type Generators
Minor Utilities
move() and forward(); swap(); Relational Operators; Comparing and Hashing type_info
Advice

35
...


35
...

All chrono facilities are in the std::chrono (sub)namespace, so we have to either explicitly qualify
with chrono:: or add a using-directive:
using namespace std::chrono;

We often want to time things or to do things that depend on timing
...


1010

Utilities

Chapter 35

If you want to know the current time_point, you can call now()
tem_clock, steady_clock, high_resolution_clock
...
do something
...
As usual, if you are not interested in details, auto is your friend:
auto t = steady_clock::now();
//
...

auto d = steady_clock::now()−t;
// something took d time units
cout << "something took " << duration_cast(d)
...
In fact, the time facilities
originated with the stringent needs of high-energy physics
...
For example, we have leap seconds, clocks that are not accurate and must be adjusted (possibly causing time
as reported by a clock to go backward), clocks of differing precision, etc
...
g
...
Consequently, the chrono facilities are not simple, but many uses of those facilities can be
very simple
...
6
...
2
...
2
...

};
duration
duration d {};
duration d {r};
duration d {d2};
d=d2
r=d
...
20
...
5)

Default constructor: d becomes {Rep{},Period{}}; constexpr
Constructor from r;
r must be convertible to Rep without narrowing; constexpr; explicit
Copy constructor: d gets the same value as d2;
d2 must be convertible to Rep without narrowing; constexpr
d gets the same value as d2; d2 must be representable as a Rep
r is the number of clock ticks in d; constexpr

We can define a duration with a specific period value
...
2
...
33};
duration> d3 {};

1011

// 7 milliseconds
// 3
...

cout << d1
...
count() << '\n';
cout << d3
...
33
// 0

Naturally, the value of count() depends on the period:
d2=d1;
cout << d1
...
count() << '\n';
if (d1!=d2) cerr<<"insane!";

// 7
// 7e+009

Here, d1 and d2 are equal but report very different count() values
...
For example:
duration d {3};
duration d {3
...
5 to int is narrowing

duration ms {3};
duration us {ms};
duration ms2 {us};

// OK
// error : we could lose many microseconds

The standard library provides meaningful arithmetic operations on durations:
r

duration (continued) (§iso
...
11
...
r
duration{d
...
r
duration{d
...
r}

d+=d2
d−=d2
d%=d2
d%=r
d∗=r
d/=r

d
...
r
d
...
r
d
...
r
...
r+=r
d
...
r+=r

The period is a unit system, so there is no = or += taking a plain value
...
Consider:

1012

Utilities

Chapter 35

duration d1 {7};
d1 += 5;
// error

// 7 milliseconds

duration> d2 {7};
d2 = 5;
// error
d2 += 5;
// error

// 7 seconds

What would 5 mean here? 5 seconds?
mean, be explicit about it
...
2
...
20
...
5)
is a Rep; arithmetic is done in the common_type of the representations

constexpr
constexpr
constexpr

d3=d+d2
d3=d−d2
d3=d%d2
d2=d%r
d2=d∗x
d2=r∗d
d2=d/x

d2=d%r
...
20
...
5)

The 0 for Rep: d=duration{duration_values::zero()};
constexpr
The smallest Rep value (less than or equal to zero()):
d=duration{duration_values::min()}; constexpr
The largest Rep value (larger than or equal to zero()):
d=duration{duration_values::max()}; constexpr
Comparison is done in the common_type of d and d2; constexpr
!(d==d2)

Comparison is done in the common_type of d and d2; constexpr
!(d>d2)

Comparison is done in the common_type of d and d2; constexpr
!(d
Convert duration d to duration type D;
no implicit conversions are used for the representation
or period; constexpr

The standard library provides some convenience aliases using the SI units from (§35
...
2
...
’’
The duration_cast is used to get a duration with a known unit of measurement
...
count() << " milliseconds\n";
auto ds = duration_cast(t2−t1);
cout << "f(x) took " << ds
...

Alternatively, we can simply (try to) construct a suitable duration:
auto t1 = system_clock::now();
f(x); // do something
auto t2 = system_clock::now();
cout << "f(x) took " << milliseconds(t2−t1)
...
count() << " microseconds\n";

// error : truncation

The precision of a clock is implementation-dependent
...
2
...

};

An epoch is a range of time determined by a
duration::zero():

clock,

measured in terms of a

duration,

starting at the

1014

Utilities

Chapter 35

time_point
time_point tp {};
time_point tp {d};
time_point tp {tp2};
d=tp
...
20
...
6)

Default constructor: start of epoch: duration::zero()
Constructor: time point d of epoch: time_point{}+d; explicit
Constructor: tp refers to the same point in time as tp2;
tp2’s duration type must be implicitly convertible to tp’s
d is tp’s stored duration
tp refers to the same point in time as tp2;
tp2’s duration type must be implicitly convertible to tp’s

For example:
void test()
{
time_point tp1(milliseconds(100));
time_point tp2(microseconds(100∗1000));
tp1=tp2;
tp2=tp1;

// error : would truncate
// OK

if (tp1!=tp2) cerr << "Insane!";
}

As for durations, meaningful arithmetic and comparisons are supported for time_points:
time_point

(continued) (§iso
...
11
...
d+=d
Move tp backward: tp
...
time_since_epoc()+d}
tp2=time_point{d+tp
...
time_since_epoc()−d}
d=duration{tp
...
time_since_epoc()}

tp2=tp
...
max()

tp2=time_point(duration::min()); static; constexpr
tp2=time_point(duration::max()); static; constexpr

tp==tp2
tp!=tp2
tptp<=tp2
tp>tp2
tp>=tp2

tp
...
time_since_epoch()
!(tp==tp2)
tp
...
time_since_epoch()
!(tp2tp2!(tp
tp2=time_point_cast(tp)

Convert the time_point tp to time_point:
time_point(duration_cast(t
...
2
...
time_since_epoch()
...
time_since_epoch()
...


35
...
3 Clocks
The time_point and duration values are ultimately obtained from hardware clocks
...
Class system_clock represents ‘‘wall clock
time’’ as obtained from a system’s real-time clock:
class system_clock {
public:
using rep = /* implementation-defined signed type */;
using period = /* implementation-defined ratio<> */;
using duration = chrono::duration;
using time_point = chrono::time_point;
//
...
We don’t explicitly deal with clock objects
...
20
...
7)
is_steady

tp=now()
t=to_time_t(tp)
tp=from_time_t(t)

Is this clock type steady?
That is, is c
...
now() for all consecutive calls of now()
and is the time between clock ticks constant? static
tp is system_clock’s time_point for the time of call; noexcept
t is the time_t (§43
...
count() << " ms";
}

1016

Utilities

Chapter 35

A system provides three named clocks:
Clock Types (§iso
...
11
...

We can determine the basic properties of the clocks like this:
cout << "min " << system_clock::duration::min()
...
count()
<< ", " << (treat_as_floating_point::value ? "FP" : "integral") << '\n';
cout << (system_clock::is_steady?"steady\n": "not steady\n");

When I ran it on one of my systems, this produced:
min −9223372036854775808, max 9223372036854775807, integral
not steady

Different systems and different clocks can give different results
...
2
...

The conversion rules for duration and time_point depend on whether their representation is floating-point (so that rounding is acceptable) or integral:
template
struct treat_as_floating_point : is_floating { };

A few standard values are provided:
duration_values
r=zero()
r=min()
r=max()

(§iso
...
11
...
2)

r=Rep(0); static; constexpr
r=numeric_limits::lowest(); static; constexpr
r=numeric_limits::max(); static; constexpr

The common type of two durations is determined by computing their greatest common denominator
(GCD):
template
struct common_type, duration> {
using type = duration::type, GCD> ;
};

Section 35
...
4

Time Traits

1017

This makes type an alias for the duration with the largest possible tick period so that both duration
arguments will convert to it without requiring a division operation
...
However, floating-point durations may have round-off errors
...
Their
is a time_point with the common_type of their durations
...
3 Compile-Time Rational Arithmetic
In , we find class ratio, which provides compile-time rational arithmetic
...
2):
template
struct ratio {
static constexpr intmax_t num;
static constexpr intmax_t den;
using type = ratio;
};

The basic idea is to encode the numerator and denominator of a rational number as (value) template
arguments
...

ratio
z=ratio_add
z=ratio_subtract
z=ratio_multiply
z=ratio_divide
ratio_equal
ratio_not_equal
ratio_less
ratio_less_equal
ratio_not_equal
ratio_greater
ratio_greater_equal

Arithmetic Operations (§iso
...
10
...
num=x::num∗y::den+y::num∗x::den; z
...
num=x::num∗y::den−y::num∗x::den; z
...
num=x::num∗y::num; z
...
num=x::num∗y::den; z
...
In , we find
the conventional notation (e
...
, + and ∗) for rational arithmetic for time (§35
...
Similarly, to help
express unit values, the standard library provides common SI magnitude names:
using yocto
using zepto
using atto
using femto
using pico
using nano
using micro
using milli
using centi
using deci
using deca
using hecto
using kilo
using mega
using giga
using tera
using peta
using exa
using zetta
using yotta

= ratio<1,1000000000000000000000000>;
// conditionally supported
= ratio<1,1000000000000000000000>;
// conditionally supported
= ratio<1,1000000000000000000>;
= ratio<1,1000000000000000>;
= ratio<1,1000000000000>;
= ratio<1,1000000000>;
= ratio<1,1000000>;
= ratio<1,1000>;
= ratio<1,100>;
= ratio<1,10>;
= ratio<10,1>;
= ratio<100,1>;
= ratio<1000,1>;
= ratio<1000000,1>;
= ratio<1000000000,1>;
= ratio<1000000000000,1>;
= ratio<1000000000000000,1>;
= ratio<1000000000000000000,1>;
= ratio<1000000000000000000000,1>;
// conditionally supported
= ratio<1000000000000000000000000,1>;
// conditionally supported

For an example of use, see §35
...
1
...
4 Type Functions
In , the standard library provides type functions (§28
...
4
...
4
...

These type functions are primarily used at compile time to support simple, and not so simple,
metaprogramming
...
4
...
Their names are mostly self-explanatory
...
20
...
4
...
4
...
20
...
4
...
To access that value, use the suffix
For example:

::value
...

}

If you tire of the ::value notation, define a constexpr function (§28
...
2):
template
constexpr bool Is_floating_point()
{
return std::is_floating_point::value;
}
template
void f(T& a)
{
static_assert(Is_floating_point(),"FP type expected");
//
...

Some type functions inquire about a combination of fundamental properties:
Composite Type Predicates (§iso
...
9
...
2)
is_reference
is_arithmetic
is_fundamental
is_object
is_scalar
is_compound
is_member_pointer

Is x a reference (lvalue or rvalue reference)?
Is x an arithmetic type (integral or floating-point; §6
...
1)?
Is x a fundamental type (§6
...
1)?
Is x an object type (not a function)?
Is x a scalar type (not a class or a function)?
Is x a compound type (!is_fundamental)?
Is x a pointer to a non-static data or function member?

These composite type predicates simply offer notational convenience
...


is_refer-

1020

Utilities

Chapter 35

Like the primary type predicates, type property predicates provide tests for fundamental aspects
of a type:
Type property predicates (§iso
...
9
...
3)
is_const
is_volatile
is_trivial
is_trivially_copyable
is_standard_layout
is_pod
is_literal_type
is_empty
is_polymorphic
is_abstract
is_signed
is_unsigned
is_constructible
is_default_constructible
is_copy_constructible
is_move_constructible
is_assignable
is_copy_assignable
is_move_assignable
is_destructible

Is X a const?
Is X a volatile (§41
...
2
...
2
...
2
...
2
...
4
...
e
...

Cont(const Cont& a)
// copy constructor
:sz(a
...
elem])
{
static_assert(Is_copy_constructable(),"Cont::Cont(): no copy");
if (Is_trivially_copyable())
memcpy(elem,a
...
begin(),a
...

}

This optimization may be unnecessary, though, because uninitialized_copy() is likely to already have
been optimized in this way
...
4
...

The type property predicates don’t do access checking depending on where they are used
...

For example:
class X {
public:
void inside();
private:
X& operator=(const X&);
˜X();
};
void X::inside()
{
cout << "inside =: " << is_copy_assignable::value << '\n';
cout << "inside ˜: " << is_destructible::value << '\n';
}
void outside()
{
cout << "outside =: " << is_copy_assignable::value << '\n';
cout << "outside ˜: " << is_destructible::value << '\n';
}

Both inside() and outside() will write 00 to report that an X is neither destructible nor copy assignable
...
6
...

Type Property Predicates (continued) (§iso
...
9
...
3)
is_trivially_constructible
is_trivially_default_constructible
is_trivially_copy_constructible
is_trivially_move_constructible
is_trivially_assignable
is_trivially_copy_assignable
is_trivially_move_assignable
is_trivially_destructible

Can X be constructed from args
using only trivial operations?
§8
...
6

For example, consider how we might optimize the destructor for a container type:
template
Cont::˜Cont()
// destructor for a container Cont
{
if (!Is_trivially_destructible())
for (T∗ p = elem; p!=p+sz; ++p)
p−>˜T();
}

1022

Utilities

Chapter 35

Type Property Predicates (continued) (§iso
...
9
...
3)
is_nothrow_constructible
is_nothrow_default_constructible
is_nothrow_copy_constructible
is_nothrow_move_constructible
is_nothrow_assignable
is_nothrow_copy_assignable
is_nothrow_move_assignable
is_nothrow_destructible
has_virtual_destructor

Can X be constructed from args
using only noexcept operations?

Does X have a virtual destructor?

Like sizeof(T), a property query returns a numeric value related to a type argument:
Type Property Queries (§iso
...
9
...

}

Here, I again used constexpr versions of the type functions returning numeric values (§28
...
2)
...
20
...
6)
is_same
is_base_of
is_convertible

Is X the same type as Y?
Is X a base of Y?
Can an X be implicitly converted to a Y?

For example:
template
void draw(T t)
{
static_assert(Is_same() || Is_base_of>(), "");
t−>draw();
}

Section 35
...
2

Type Generators

1023

35
...
2 Type Generators
In , the standard library provides type functions for producing a type given other types
as arguments
...
20
...
7
...
To access that type, use the suffix ::type
...

};

If you tire of the ::type define a type alias (§28
...
1):
template
using Add_const = typename add_const::type;
template
class My_map {
{
pair,V> default_node;
//
...

Reference Modification (§iso
...
9
...
2, §iso
...
9
...
6)
remove_reference
add_lvalue_reference
add_rvalue_reference
decay

If X is a reference type, the referred-to type; otherwise, X
If X is an rvalue reference Y&&, Y&; otherwise, X&
If X is a reference, X; otherwise, X&& (§7
...
3)
The type passed by value for a function argument of type X

The decay functions handles array decay as well as reference dereferencing
...
For example:

1024

Utilities

Chapter 35

template
void f(T v)
{
Remove_reference x = v; // copy of v
T y = v;
// maybe copy of v; maybe a reference to x
++x;
// increment local variable
++y;
//
...

Sign Modification (§iso
...
9
...
3)
make_signed

make_unsigned

Remove any (explicit or implied) unsigned modifier
and add signed;
X must be an integral type (except bool or an enumeration)
Remove any (explicit or implied) signed modifier
and add unsigned;
X must be an integral type (except bool or an enumeration)

For built-in arrays, we sometimes want to get the element type or to remove a dimension:
Array Modification (§iso
...
9
...
4)
remove_extent
remove_all_extents

If X is an array type, the element type; otherwise X
If X is an array type, the base type
(after removing all array modifiers); otherwise X

For example:
int a[10][20];
Remove_extent a10; // an array[10]
Remove_all_extents i;
// an int

We can make a pointer type pointing to an arbitrary type, or find the pointed-to type:
Pointer Modification (§iso
...
9
...
5)
remove_pointer
add_pointer

For example:

If X is a pointer type, the pointed-to
remove_reference::type∗

type; otherwise X

Section 35
...
2

Type Generators

1025

template
void f(T x)
{
Add_pointer p = new Remove_reference{};
T∗ p = new T{};
// would not work if T is a reference
//
...
2
...
20
...
7
...
>

The standard mentions this as a possible implementation of aligned_storage:
template
struct aligned_storage {
using type = struct { alignas(A) unsigned char data[N]; };
};

// N chars aligned to A (§6
...
9)

The final type functions for type selection, computing common types, etc
...
20
...
7
...
5
...
2) for most uses

enable_if
conditional

enable_if
T if b==true; otherwise F

common_type

The common type of all types of a parameter pack X;
two types are common if they can be used as true
and false types of a ?:-expression
X’s underlying type (§8
...
3
...
1 and §28
...

It is often useful to find a type that can be used for operations on more than one type, such as
the result of an addition of two values of related but different types
...
A type is the common type of itself (obviously):

1026

Utilities

Chapter 35

template ...
1
...

The common type for N types is found by applying the rules for N==1 and N==2 recursively:
template ...
> {
using type = typename common_type::type, V
...
9;
Result_of r4 = "Hero";
Result_of r5 = 'a';

// r1 is a int
// r2 is a bool
// r3 is a double
// r4 is a string
// r5 is a char

Section 35
...
2

Type Generators

1027

Note that Result_of can distinguish between the two versions of Fct::operator()()
...
For example:
int f();
string f(int);
Result_of r1 = 7;

// function
// error : no overload resolution for pointer to function

Unfortunately, we don’t do overload resolution for pointers to functions, but why did I use
Result_of in such a roundabout way, instead of:
Result_of r1 = 7;

// error : no argument specification,
// and ff is a function rather than a type
// error : the argument to Result_of must be a type
// error : decltype(f) is a function type
// rather than a pointer to function type
// OK: r3 is an int

Result_of r1 = 7;
Result_of r2 = 7;
Result_of r3 = 7;

Naturally, Result_of is usually found in templates where we can’t easily look up the answer in the
program text
...

}
void f4()
{
temp(ff,1);
temp(fx,'a');
temp(Fct(),"Ulysses");
}

Note that the function ff is converted to a pointer function in the call, so the reliance on pointers to
functions in Result_of isn’t as odd as it may seem at first
...
20
...
4)

Returns an rvalue for T: typename add_rvalue_reference::type;
never use a return value of declval

The declval() type function is unusual in the standard library because it is actually a function (without users needing to wrap it)
...
The intent is to use
declval as a type where the type of a variable of type X is needed
...
size(); ++i)
swap((∗this)[i],a[i]);
}

See also the definition of common_type
...
5 Minor Utilities
These utilities are minor in size, but not in importance
...


35
...
1 move() and forward()
In , we find some of the most useful small functions:
Other Transformations (§iso
...
9
...
6)
x2=forward(x)
x2=move(x)
x2=move_if_noexcept(x)

is an rvalue; x may not be an lvalue; noexcept
is an rvalue; noexcept
If x can be moved, x2=move(x); otherwise x2=x; noexcept

x2
x2

A move() is simply a cast to an rvalue:
template
Remove_reference&& move(T&& t) noexcept
{
return static_cast&&>(t);
}

In my opinion, move() should have been called rvalue(), because it doesn’t actually move anything
...

A move() is used to tell the compiler that an object will not be used anymore in a context, so that
its value can be moved and an empty object left behind
...
5
...

A forward() produces an rvalue from an rvalue only:
template
T&& forward(Remove_reference& t) noexcept
{
return static_cast(t);
}
template
T&& forward(Remove_reference&& t) noexcept;
{
static_assert(!Is_lvalue_reference,"forward of lvalue");
return static_cast(t);
}

This pair of forward() functions are meant always to be available together, and selection between
them should be done by overload resolution
...
For example:
int i = 7;
forward(i);
forward(7);

// call first version
// call second version

The assert is there for programmer who are too clever for their own good and calls the second version with an explicit template argument and an lvalue
...
5
...
5
...
1, §28
...
3)
...
3
...

Use move() when the intent is to ‘‘steal the representation’’ of an object with a move operation,
and use forward() for forwarding
...
The only safe use of an x after a move(x) is destruction or
as a target for an assignment
...
However, don’t rely on that unless you really know
...
5
...
20
...
2)
swap(x,y)

swap(a1n,a2n)

Exchange the values of x and y;
x and y are passed as non-const references;
noexcept if x’s and y’s copy operations are noexcept
a1n and a2n are passed as references to arrays: T(&)[N];
noexcept if ∗a1n and ∗a2n’s copy operations are noexcept

The relatively obvious implementation swap() is:
template
void swap(T& a, T& b) noexcept(Is_nothrow_move_constructible()
&& Is_nothrow_move_assignable())
{
T tmp {move(a)};
a = move(b);
b = move(tmp);
}

This implies that swap() cannot be used to exchange rvalues:
vector v1 {1,2,3,4};
swap(v,vecor{});
v
...
5
...
20
...
1)
x!=y
x>y
x<=y
x>=y

!(x==y)
y!(y!(x
This requires that the programmer has made sure that x==y and x ...
d==d; }
};
void my_algo(vector& vv)
{
using namespace std::rel_ops;
for (int i=0; i ...
In particular:
namespace Mine {
struct Val {
double d;
bool operator==(Val v) const { return v
...
2
...
A safer approach is to
place using-directives in local scopes
...
5
...

type_index is created from a type_info (§22
...

type_index

Operations (§iso
...
13)

is a pointer to the type_info represented by a type_index
type_index ti {tinf};
ti represents the type_info tinf; noexcept
ti==ti2
ti and ti2 represent the same type_info: ∗ti
...
tip); noexcept
ti!=ti2
!(ti==ti2); noexcept
titi
...
tip); noexcept
ti<=ti2
!ti2
...
tip); noexcept
ti>ti2
ti2
...
tip); noexcept
ti>=ti2
!ti
...
tip); noexcept
tip

n=ti
...
tip−>hash_code()
p = ti
...
4
...
4)

A

Section 35
...
4

Comparing and Hashing type_info

unordered_map types;
//
...
6 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]

Use facilities, such as steady_clock, duration, and time_point for timing; §35
...

Prefer facilities over facilities; §35
...

Use duration_cast to get durations in known units of time; §35
...
1
...
2
...

You can inquire about properties of types at compile time; §35
...
1
...
5
...

Use forward() for forwarding; §35
...
1
...

– Strunk & White







Introduction
Character Classification
Classification Functions; Character Traits
Strings
string vs
...
1 Introduction
The standard library offers character classification operations in (§36
...
3), regular expression matching in (Chapter 37), and support for C-style strings in (§43
...
Handling of different character sets, encodings, and
conventions (locales) is discussed in Chapter 39
...
3
...
2 Character Classification
The standard library provides classification functions to help users to manipulate strings (and other
character sequences) and traits specifying properties of a character type to help implementers of
operations on strings
...
2
...
'z', 'A'
...
'9')?
Is c hexadecimal digit (decimal digit or 'a'
...
'F')?
Is c an uppercase letter?
Is c a lowercase letter?
isalpha(c) or isdigit(c)
Is c a control character (ASCII 0
...
'˜')?
isalpha(c) or isdigit(c) or ispunct(c)? note: not space

In addition, the standard library provides two useful functions for removing case differences:
Upper- and Lowercase
toupper(c)
tolower(c)

c
c

or c’s uppercase equivalent
or c’s lowercase equivalent

The equivalent functions for wide characters are provided in
...
5
...
5
...
Equivalent functions for other locales are provided in (§39
...
1)
...
For example, a novice might write:
if ('a'
This is more verbose (and most likely slower) than:
if (islower(ch))

// a lowercase character

Also, there is no guarantee that the characters are contiguous in a code space
...


Section 36
...
2

Character Traits

1035

36
...
2 Character Traits
As shown in §23
...
However, efficiency can be improved and implementations can be simplified for
types that don’t have user-defined copy operations
...
2
...
This also helps to make I/O of strings simple
and efficient
...
A char_traits is a specialization
of the template:
template struct char_traits { };

All

char_traits are defined in std, and the standard ones are presented in
...
Consider char_traits:
template<>
struct char_traits {
// char_traits operations should not throw exceptions
using char_type = char;
using int_type = int;
// type of integer value of character
using off_type = streamoff;
// offset in stream
using pos_type = streampos;
// position in stream
using state_type = mbstate_t;
// multibyte stream state (§39
...
6)
//
...
21
...
3):
template<> struct char_traits;
template<> struct char_traits;
template<> struct char_traits;
template<> struct char_traits;

The members of the standard char_traits are all static functions:
char_traits static
c=to_char_type(i)
i=to_int_type(c)
eq_int_type(c,c2)
eq(c,c2)
lt(c,c2)
i=compare(p,p2,n)
assign(c,c2)
p2=assign(p,n,c)
p3=move(p,p2,n)
p3=copy(p,p2,n)

Members (§iso
...
2)

int_type to char_type conversion
char_type to int_type conversion
to_int_type(c)==to_int_type(c2)
Is c treated as equal to c2?
Is c treated as less than c2?
Lexicographical compare of [p:p+n) and [p2:p2+n)
c=c2 for char_type
Assign n copies of c to [p:p+n); p2=p
Copy [p:p+n) to [p2:p2+n); [p:p+n) and [p2:p2+n) may
Copy [p:p+n) to [p2:p2+n); [p:p+n) and [p2:p2+n) may

overlap; p3=p
not overlap; p3=p

1036

Strings

Chapter 36

char_traits static
n=length(p)
p2=find(p,n,c)
i=eof()
i=not_eof(i)

Members (§iso
...
2)

n is the number of characters in [p:q)
where ∗q is the first element so that eq(q,charT{})
p points to the first occurrence of c in [p:p+n) or nullptr
i is the int_type value representing end-of-file
i if !eq_int_type(i,eof()); otherwise i can be any value not equal to eof()

Comparing with eq() is often not simply an ==
...

Because copy() does not protect against overlapping ranges, it may be faster than move()
...
It returns an int, where 0 represents an exact match, a negative number means that its first argument comes lexicographically
before the second, and a positive number means that its first argument comes after its second
...
6)
...
3 Strings
In , the standard library provides a general string template basic_string:
templatetypename Tr = char_traits,
typename A = allocator>
class basic_string {
public:
using traits_type = Tr;
using value_type = typename Tr::char_type;
using allocator_type = A;
using size_type = typename allocator_traits
::size_type;
using difference_type = typename allocator_traits
::difference_type;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = typename allocator_traits
::pointer;
using const_pointer = typename allocator_traits
::const_pointer;
using iterator = /* implementation-defined */;
using const_iterator = /* implementation-defined */;
using reverse_iterator = std::reverse_iterator;
using const_reverse_iterator = std::reverse_iterator;
static const size_type npos = −1;

// integer representing end-of-string

//
...

The basic_string offers the strong guarantee (§13
...


Section 36
...

Like containers (Chapter 31), basic_string is not meant to be used as a base class and offers
move semantics so that it can be efficiently returned by value
...
3
...
C-Style Strings
I assume some familiarity with string from the many examples in this book, so I start with a few
examples contrasting string use with the use of C-style strings (§43
...

Consider making up an email address by concatenating a user identifier and a domain name:
string address(const string& identifier, const string& domain)
{
return identifier + '@' + domain;
}
void test()
{
string t = address("bs","somewhere");
cout << t << '\n';
}

This is trivial
...
A C-style string is a pointer to an array of
zero-terminated characters
...
At least it gave the output I expected
...
However, experience (i
...
, error logs) shows that this is not always the case
...
The implementation of the C-style address() contains a lot of tricky pointer
manipulation, and its use requires the caller to remember to free the returned memory
...
However, for most
uses, the string does fewer allocations and deallocations than a C-style equivalent (because of the
small-string optimization and move semantics; §19
...
3, §19
...
1)
...
In the example, this implies that the C-style code traverses each input string twice, whereas the string version does only one traversal per input
...

The fundamental difference between C-style strings and string is that string is a proper type with
conventional semantics, whereas the C-style string is a set of conventions supported by a few useful
functions
...
begin(),vs
...
7
...


Section 36
...
2

Constructors

1039

36
...
2 Constructors
A basic_string offers a bewildering variety of constructors:
x

basic_string Constructors (§iso
...
4
...
˜basic_string()

Destructor: free all resources
Copy: s gets the characters from x
Move: s2 gets the characters from s; noexcept

s=x
s2=move(s)

basic_string s {s2,pos,n,A{};}
basic_string s {s2,pos,string::npos,A{}};
Initialize s from [p:p+n); p is a C-style string; use allocator a
basic_string s {p,n,A{}};
s holds n copies of the character c; use allocator a
basic_string s {n,c,A{};}
s gets the characters from [b:e); use allocator a
basic_string s {b,e,A{}};

The most common variants are also the simplest:
string s0;
string s1 {"As simple as that!"};
string s2 {s1};

// the empty string
// construct from C-style string
// copy constructor

Almost always, the destructor is implicitly invoked
...
At best, you get a nasty run-time error
...


1040

Strings

Chapter 36

If you try to construct a string with more characters than your implementation can handle, the
constructor throws std::length_error
...
’’ For example:
string ss {"Fleetwood Mac"};
string ss2 {ss,0,9};
string ss3 {ss,10,string::npos};

string’s

length and is generally used to mean

// "Fleetwood"
// "Mac"

Note that the substring notation is (position,length) rather than [start,end)
...
A user-defined literal could be used for that (§19
...
6), for
example, "The Beatles"s and "Elgar"s
...


36
...
3 Fundamental Operations
A basic_string offers comparisons, control of size and capacity, and access operations
...
21
...
8)
s or s2 but not both can be a C-style string
s==s2
s!=s2
ss<=s2
s>s2
s>=s2

Is s equal to s2? compares character values using traits_type
!(s==s2)
Is s lexicographically before s2?
Is s lexicographically before or equal to s2?
Is s lexicographically after s2?
Is s lexicographically after or equal to s2?

For more comparison operations, see §36
...
8
...
3
...
21
...
4)

n=s
...
length()
n=s
...
resize(n,c)
s
...
reserve(n)
s
...
capacity()

n is the number of characters in s
n=s
...
size()
Make s
...
resize(n,C{})
Ensure that s can hold n characters without further
No effect: s
...
shrink_to_fit()
s
...
empty()
a=s
...
capacity==s
...


Section 36
...
3

Fundamental Operations

1041

An example:
void fill(istream& in, string& s, int max)
// use s as target for low-level input (simplified)
{
s
...
read(&s[0],max);
const int n = in
...
resize(n);
s
...
That’s sloppy
...
at(i)

Access (§iso
...
4
...
at(i) is a reference to the ith element of s;
throw range_error if s
...
front()
s
...
size()−1]

s
...
pop_back()
s+=x

Append the character c
Remove the last character from s: s
...
size()−1)
Append x at the end of s; x can be a character, a string,
a C-style string, or an initializer_list
Concatenation: optimized version of s=s1; s+=s2;
s gets the characters from s2[pos:n2)
where n2 is min(n,s
...
size()s gets all the characters from s2; n=s
...
copy(s2,n,pos)

n2=s
...
c_str()
p=s
...
c_str()

s
...
swap(s2)

An out-of-range access using at() throws std::out_of_range
...

There is no implicit conversion of a string to a char∗
...
Instead, the standard library provides the explicit conversion function c_str() to
const char∗
...
g
...
Using a function, such as strcmp(), that
assumes C-style string conventions on the result of s
...
data() on a string containing a zero
character may cause surprise
...
3
...
4
...
4
...
21
...
8
...

A getline() removes its terminator character (by default '\n') from the input stream but does not
enter it into the string
...
For example:
vector lines;
for (string s; getline(cin,s);)
lines
...
For example:
string first_name;
string second_name;
cin >> first_name >> second_name;

The string target of an input operation is set to empty before reading and expands to hold the characters read
...
3)
...
3
...
The desired
numeric types are encoded in the function names:
Numeric Conversions (§iso
...
5) (continues)
s can be a string or a wstring
x=stoi(s,p,b)

x=stoi(s,p)
x=stoi(s)
x=stol(s,p,b)
x=stoul(s,p,b)
x=stoll(s,p,b)
x=stoull(s,p,b)

String to int; x is an integer; read starting with s[0]
if p!=nullptr, ∗p is set to the number of characters used for x;
b is the base of the number (between 2 and 36, inclusive)
x=stoi(s,p,10); decimal numbers
x=stoi(s,nullptr,10); decimal numbers; don’t report the character count
String to long
String to unsigned long
String to long long
String to unsigned long long

Section 36
...
5

Numeric Conversions

1043

Numeric Conversions (continued) (§iso
...
5)
s can be a string or a wstring
x=stof(s,p)
x=stod(s,p)
x=stold(s,p)
s=to_string(x)
ws=to_wstring(x)

String to float
String to double
String to long double
s is a string representation of x; x must be an integer or floating-point value
s is a wstring representation of x; x must be an integer or floating-point value

Each of these sto∗ (String to) functions has three variants, like stoi
...
45";
auto x1 = stoi(s);
auto x2 = stod(s);

// x1 = 123
// x2 = 123
...
For example:
string ss = "123
...
I prefer to use a
string_stream (§38
...
2)
...
For example:
string s = " 123
...
Any further base value
will be an error or an extension
...
If it finds a number that it cannot represent in its target type, it
throws out_of_range; in addition, the conversions to floating-point types set errno to ERANGE
(§40
...
For example:
stoi("Hello, World!");
stoi("12345678901234567890");
stof("123456789e1000");

// throws std::invalid_argument
// throws std::out_of_range; errno=ERANGE
// throws std::out_of_range; errno=ERANGE

1044

Strings

Chapter 36

The sto∗ functions encode their target type in their names
...
In such cases, consider to (§25
...
5
...


36
...
6 STL-like Operations
The basic_string provides the usual set of iterators:
String Iterators (§iso
...
4
...
begin()
p=s
...
cbegin()
p=s
...
rbegin()
p=s
...
crbegin()
p=s
...
For example:

strings

can

void f(string& s)
{
auto p = find_if(s
...
end(),islower);
//
...
Hopefully, these versions
will be optimized for strings beyond what would be easy to do for general algorithms
...
General
algorithms tend to assume that the elements of a container are meaningful in isolation
...

A basic_string offers complex assignment()s:
basic_string Assignment (§iso
...
4
...
3)
All operations return the string to which they are applied
s
...
assign(move(s2))
s
...
assign(p,n)
s
...
assign(b,e)

s=x; x can be a string, a C-style string, or an initializer_list
Move: s2 is a string; noexcept
s gets the characters s2[pos:pos+n)
s gets the characters [p:p+n); p is a C-style string
s gets n copies of the character c
s gets the characters from [b:e)

We can insert(), append(), and erase() in a basic_string:

Section 36
...
6

STL-like Operations

1045

Insertion and Deletion (§iso
...
4
...
2, §iso
...
4
...
4, §iso
...
4
...
5)
All operations return the string to which they are applied

basic_string

s
...
append(b,e)
s
...
append(p,n)
s
...
insert(pos,x)
s
...
insert(p,n,c)
insert(p,b,e)
s
...
erase(pos,n)

Append x at the end of s; x can be a character, a string,
a C-style string, or an initializer_list
Append [b:e) at the end of s
Append s2[pos:pos+n) to the end of s
Append the characters [p:p+n) to the end of s; p is a C-style string
Append n copies of character c to the end of s
Insert x before s[pos]; x can be a character, a string,
a C-style string, or an initializer_list
Insert c before iterator p
Insert n copies of c before iterator p
Insert [b:e) before iterator p
Remove trailing characters from s, starting with s[pos];
s
...
size() becomes max(pos,s
...
find(' ');
s
...

In the following, I use s[b:e) to denote a sequence of elements [b:e) in s:
basic_string Replace (§iso
...
4
...
6) (continues)
All operations return the string to which they are applied
s
...
replace(pos,n,p,n2)
s=s
...
replace(pos,n,n2,c)

Replace s[pos:pos+n) with s2[pos2:pos2+n2)
Replace s[pos:pos+n) with [p:p+n2);
s2 is a string or a C-style string
Replace s[pos:pos+n) with s2;
s2 is a string or a C-style string
Replace s[pos:pos+n) with n2 copies of the character c

1046

Strings

Chapter 36

Replace (continued) (§iso
...
4
...
6)
All operations return the string to which they are applied

basic_string

s
...
replace(b,e,p,n)
s
...
replace(b,e,b2,e2)

Replace [b:e) with x; x is a string, a C-style string,
or an initializer_list
Replace [b:e) with [p:p+n)
Replace [b:e) with n copies of the character c
Replace [b:e) with [b2:e2)

The replace() replaces one substring with another and adjusts the
example:

string’s

size accordingly
...
replace(0,4,"");
// erase initial "but "
s
...
find("even"),4,"only");
s
...
find(" don't"),6,"");
// erase by replacing with ""
assert(s=="I have heard it works only if you believe in it");
}

Code relying on ‘‘magic’’ constants like the number of characters to be replaced is error-prone
...
This can be used for chaining operations:
void f2()
{
string s = "but I have heard it works even if you don't believe in it";
s
...
replace(s
...
replace(s
...
3
...
As usual,
s
...
end()
...
’’
x

find()
find

searches from
functions use

basic_string Find Element (§iso
...
4
...
2)
can be a character, a string, or a C-style string
...
find(x)

Find x in s; pos is the index of the first character found or string::npos

pos=s
...
find(p,pos2,n)

pos=find(basic_string(s,pos2)
pos=s
...
rfind(x,pos2)

Find x in s[0:pos2); pos is the position of the first character
of the x closest to the end of s or string::npos

pos=s
...
rfind(p,pos2,n)

pos=s
...
rfind(basic_string{p,n},pos2)

Section 36
...
7

The find Family

1047

For example:
void f()
{
string s {"accdcde"};
auto i1 = s
...
rfind("cd");

// i1==2
// i2==4

s[2]=='c' && s[3]=='d'
s[4]=='c' && s[5]=='d'

}

The find_∗_of() functions differ from find() and rfind() by looking for a single character, rather than a
whole sequence of characters:
x

basic_string Find Elements from a Set (§iso
...
4
...
4)
can be a character, a string, or a C-style string; p is a C-style string
...


pos2=s
...
size());
pos2 is the position of the first character from x
in s[pos:s
...
find_first_of(x)
pos2=s
...
find_first_of(s2,0)
pos2=s
...
find_last_of(x,pos)

Find a character from x in s[0:pos);
pos2 is the position of the character from x
closest to the end of s or string::npos

pos=s
...
find_last_of(p,pos,n)

pos=s
...
find_last_of(pos2,basic_string{p,n})

pos2=s
...
size());
pos2 is the position of the first character from x
not in s[pos:s
...
find_first_not_of(x)
pos2=s
...
find_first_not_of(s2,0)
pos2=s
...
find_last_not_of(x,pos)

Find a character not from x in s[0:pos);
pos is the position of the character
from x closest to the end of s or string::npos

pos=s
...
find_last_not_of(p,pos,n)

pos=s
...
find_last_not_of(pos,basic_string{p,n})

For example:
string s {"accdcde"};
auto i1 = s
...
rfind("cd");

// i1==2
// i2==4

s[2=='c' && s[3]=='d'
s[4]=='c' && s[5]=='d'

auto i3 = s
...
find_last_of("cd");
auto i5 = s
...
find_last_not_of("cd");

// i3==1
// i4==5
// i5==0
// i6==6

s[1]=='c'
s[5]=='d'
s[0]!='c' && s[0]!='d'
s[6]!='c' && s[6]!='d'

1048

Strings

Chapter 36

36
...
8 Substrings
A basic_string offers a low-level notion of substring:
basic_string
s2=s
...
substr(pos)
s2=s
...
21
...
7
...
size()−n,n)
s2=s
...
substr(0,string::npos)

Note that substr() creates a new string:
void user()
{
string s = "Mary had a little lamb";
string s2 = s
...
21
...
7
...
compare(s2)

A lexicographical comparison of s and s2;
using char_traits::compare() for comparison;
n=0 if s==s2; n<0 if s0 if s2>s; noexcept;

n2=s
...
compare(pos,n,s2,pos2,n2)

n2=basic_string{s,pos,n}
...
compare(basic_string{s2,pos2,n2})

n=s
...
compare(basic_string{p});
p is a C-style string
n2=basic_string{s,pos,n}
...
compare(pos,n,p)
n2=s
...
substr(0,4);
// s2 == "Mary"
auto i1 = s
...
compare(0,4,s2); // i2==0
}

This explicit use of constants to denote positions and lengths is brittle and error-prone
...
4

Advice

1049

36
...
2
...

If you implement string-like abstractions, use character_traits to implement operations on
characters; §36
...
2
...
3
...
3
...
3
...

Return strings by value (rely on move semantics); §36
...
2
...
3
...

Do not pass a nullptr to a string function expecting a C-style string; §36
...
2
...
3
...

Use at() rather than iterators or [] when you want range checking; §36
...
3, §36
...
6
...
3
...
3
...

If you use strings, catch length_error and out_of_range somewhere; §36
...
3
...
3
...

string input is type sensitive and doesn’t overflow; §36
...
4
...
3
...

Use the find() operations to locate values in a string (rather than writing an explicit loop);
§36
...
7
...
3
...


This page intentionally left blank

37
Regular Expressions
If the code and the comments disagree,
then both are probably wrong
...
1 Regular Expressions
In , the standard library provides regular expressions:
• regex_match(): Match a regular expression against a string (of known size)
...

• regex_replace(): Search for strings that match a regular expression in an (arbitrarily long)
stream of data and replace them
...

• regex_token_iterator: iterate over non-matches
...
txt");
// input file
if (!in) cerr << "no file\n";
regex pat {R"(\w{2}\s∗\d{5}(−\d{4})?)"};

// U
...
postal code pattern

int lineno = 0;
for (string line; getline(in,line);) {
++lineno;
smatch matches; // matched strings go here
if (regex_search(line, matches, pat)) {
cout << lineno << ": " << matches[0] << '\n'; // the complete match
if (1 ...
matched)
cout << "\t: " << matches[1] << '\n'; // submatch
}
}
}

This function reads a file looking for U
...
postal codes, such as TX77845 and DC 20500−0001
...
Here, matches[0] is the whole pattern and matches[1] is
the optional four-digit subpattern
...
3
...
1) which is particularly suitable for
regular expressions because they tend to contain a lot of backslashes
...
S
...
The regex type performs this compilation at run time
...
1
...
2)
...

The syntax of regular expressions is based on characters with special meaning:
Regular Expression Special Characters

...
1
...

A pattern can be optional or repeated (the default is exactly once) by adding a suffix:
Repetition
{n}
{ n, }
{n,m}

+
?

Exactly n times
or more times
At least n and at most m times
Zero or more, that is, {0,}
One or more, that is, {1,}
Optional (zero or one), that is {0,1}

n

For example:
A{3}B{2,4}C∗

Examples that match:
AAABBC
AAABBB

Example that do not match:
AABBC
AAABC
AAABBBBBCCC

// too few As
// too few Bs
// too many Bs

A suffix ? after any of the repetition notations makes the pattern matcher ‘‘lazy’’ or ‘‘non-greedy
...
By
default, the pattern matcher always looks for the longest match (similar to C++’s Max Munch rule;
§10
...
Consider:
ababab

The pattern (ab)∗ matches all of ababab
...


1054

Regular Expressions

Chapter 37

The most common character classifications have names:
Character Classes
Any alphanumeric character
Any alphabetic character
Any whitespace character that is not a line separator
Any control character
Any decimal digit
Any decimal digit
Any graphical character
Any lowercase character
Any printable character
Any punctuation character
Any whitespace character
Any whitespace character
Any uppercase character
Any word character (alphanumeric characters plus the underscore)
Any hexadecimal digit character

alnum
alpha
blank
cntrl
d
digit
graph
lower
print
punct
s
space
upper
w
xdigit

Several character classes are supported by shorthand notation:
Character Class Abbreviations
\d
\s
\w
\D
\S
\W

A decimal digit
A space (space, tab, etc
...

As an example, consider writing a pattern that describes C++ identifiers: an underscore or a letter followed by a possibly empty sequence of letters, digits, or underscores
...

// wrong: doesn’t accept underscore ('_' is not alpha)
// wrong: underscore is not part of alnum either

Section 37
...
1

Regular Expression Notation

([[:alpha:]]|_)([[:alnum:]]|_)∗
[[:alpha:]_][[:alnum:]_]∗
[_[:alpha:]][_[:alnum:]]∗
[_[:alpha:]]\w∗

1055

// OK, but clumsy
// OK: include the underscore in the character classes
// also OK
// \w is equivalent to [_[:alnum:]]

Finally, here is a function that uses the simplest version of regex_match() (§37
...
1) to test whether a
string is an identifier:
bool is_identifier(const string& s)
{
regex pat {"[_[:alpha:]]\\w∗"};
return regex_match(s,pat);
}

Note the doubling of the backslash to include a backslash in an ordinary string literal
...
2
...
3, §6
...
3
...
28
...
2, §37
...
2)
\b
\B
\i

The first or last character of a word (a ‘‘boundary character’’)
Not a \b
The ith sub_match in this pattern

Using raw string literals alleviates many problems with special characters
...
If
you need parentheses that should not define a subpattern, use (? rather than plain (
...

Regular Expression Grouping Examples
\d∗\s\w+
(\d∗)\s(\w+)
(\d∗)(\s(\w+))+
(\s∗\w∗)+
<(
...
It finds tag/end-of-tag markers
...
∗?, for the subpattern between the tag and the end tag
...
∗, this input would have caused a problem:
Always look for the bright side of life
...
A greedy match on
the second subpattern would match the first with the last
...

It is possible to vary details of the regular expression notation using options (§37
...
For example, if regex_constants::grep is used, a?x:y is a sequence of five ordinary characters because ? does
not mean ‘‘optional’’ in grep
...


37
...
2

regex

1057

˜basic_regex(); // not virtual; basic_regex is not meant to be used as a base class
//
...
5
...
28
...
1)

No case is used when matching
No subexpression matches are stored in the match results
Prefer fast matching to fast regular expression object construction
Character ranges of the form [a−b] are locale sensitive
The regular expression grammar is the one used by ECMAScript
in ECMA-262 (with minor modifications; §iso
...
13)
The regular expression grammar is the one used by
basic regular expressions in POSIX
The regular expression grammar is the one used by
extended regular expressions in POSIX
The regular expression grammar is the one used by POSIX awk
The regular expression grammar is the one used by POSIX grep
The regular expression grammar is the one used by POSIX grep -E

Use the default unless you have a good reason not to
...

A regex object can be constructed from a string or similar sequence of characters:
basic_regex
basic_regex r {};
basic_regex r {x,flags};

basic_regex r {x};
basic_regex r {p,n,flags};
basic_regex r {p,n};
basic_regex r {b,e,flags}
basic_regex r {b,e};

Constructors (§iso
...
8
...
3), but there are also
a few operations on regex itself:

1058

Regular Expressions

Chapter 37

basic_regex
r=x
r=move(r2)
r=r
...
assign(x,flags)

Operations (§iso
...
8)

Copy assignment: x can be a basic_regex,
a C-style string, a basic_string, or an initializer_list
Move assignment
Copy or move
Copy or move; set r’s flags to flags x can be a basic_string,
a C-style string, or an initializer_list

r=r
...
assign(p,n,flags)
r=r
...
assign(b,e)

Set r’s pattern to [p:p+n) and r’s flags to flags
Set r’s pattern to [b:e) and r’s flags to flags

r=r
...
mark_count()
x=r
...
imbue(loc)
loc=r
...
swap(r2)

n is the number of marked subexpressions in r
x is r’s flags
r gets the locale loc; loc2 is r’s previous locale
loc is r’s locale
Exchange values of r and r2

r=r
...
If you need to output
a pattern, keep a copy of the string used to initialize
...
2
...

};

must be a bidirectional iterator (§33
...
2)
...


Bi

Section 37
...
1

Match Results

sub_match
sub_match sm {};
n=sm
...
str()
x=sm
...
matched

Operations

Default constructor: an empty sequence; constexpr
n is the number of characters matched
Implicit conversion of a sub_match to a basic_string;
s is a basic_string containing the characters matched
s is a basic_string containing the characters matched
Lexicographical comparison: sm
...
compare(x);
x can be a sub_match, a basic_string, or a C-style string
Is x equal to y? x and y can be a sub_match or a basic_string
!(x==y)
x is lexicographically
y!(x>y)
!(xtrue

before y

if sm contains a match; false otherwise

For example:
regex pat ("<(
...

A match_results is a container of sub_matches:
template>
class match_results {
public:
using value_type = sub_match;
using const_reference = const value_type&;
using reference = const_reference;
using const_iterator = /* implementation-defined */;
using iterator = const_iterator;
using difference_type = typename iterator_traits::difference_type;
using size_type = typename allocator_traits
::size_type;
using allocator_type = A;
using char_type = typename iterator_traits::value_type;
using string_type = basic_string;
˜match_results();

// not virtual

//
...
1
...


1059

1060

Regular Expressions

As for basic_string
match_results:

Chapter 37

and basic_ostream, a few standard aliases are provided for the most common

using cmatch = match_results;
using wcmatch = match_results;
using smatch = match_results;
using wsmatch = match_results;

// C-style string
// wide C-style string
// string
// wstring

A match_results provides access to its match string, its sub_matches, and the characters before and
after the match:
m[0]
m
...


m[m
...
suffix()

A match_results provides a conventional set of operations:
regex
match_results m {};
match_results m {a};
match_results m {m2};
m2=m
m2=move(m)
m
...
ready()
n=m
...
max_size()
m
...
length(i)
n=m
...
position(i)
pos=m
...
str(i)
s=m
...
prefix()
sm=m
...
28
...
28
...
size()==0?
r is a const reference to the ith sub_match of m;
m[0] represents the complete match;
if i>= size(), m[i] refers to a sub_match representing
an unmatched subexpression
...
length(); the number of characters of m[i]
n=m
...
first; the first character of m[i]
pos=position(0)
s=m[i]
...
str(0)
sm is a sub_match representing the characters

not matched
by m in the input string coming before the match
sm is a sub_match representing the characters not matched
by m in the input string coming after the match

Section 37
...
1

regex

Match Results

1061

Matches and Submatches (continued)(§iso
...
9, §iso
...
10)
points to the first sub_match of m
points to the one-beyond-the-last sub_match of m
points to the first sub_match of m (const iterator)
points to the one-beyond-the-last sub_match of m (const iterator)
a is m’s allocator
Exchange the states of m and m2
Are the values of sub_matches of m and m2 equal?

p=m
...
end()
p=m
...
cend()

p
p
p
p

a=m
...
swap(m2)
m==m2
m!=m2

!(m==m2)

We can subscript a regex_match to access a sub_match, for example, m[i]
...
For example:
void test()
{
regex pat ("(AAAA)(BBB)?");
string s = "AAAA";
smatch m;
regex_search(s,m,pat);
cout << boolalpha;
cout << m[0]
...
matched << '\n';
cout << m[2]
...
matched << '\n';

// true: we found a match
// true: there was a first sub_match
// false: no second sub_match
// false: there couldn’t be a third sub_match for pat

}

37
...
2 Formatting
In regex_replace(), formatting is done using a format() function:
regex Formatting (§iso
...
10
...
format(out,b,e,flags)

Copy [b:e) to out;
substituting submatches from m for format characters

out=m
...
format(out,fmt,flags)

out=m
...
format(out,begin(fmt),end(fmt),flags);
fmt can be a basic_string or a C-style string
out=m
...
format(fmt,regex_constants::format_default)

out=m
...
format(fmt,flags)

s=m
...
g
...
g
...
3
...

The details of formatting done by format() are controlled by a set of options (flags):
regex

Formatting Options (regex_constants::match_flag_type; §iso
...
5
...
28
...
3 Regular Expression Functions
The functions for applying regular expression patterns to data are regex_search() for searching in a
sequence of characters, regex_match() for matching a fixed-length sequence of characters, and
regex_replace() for doing replacement of patterns
...
28
...
2)

match_not_bol
match_not_eol
match_not_bow
match_not_eow
match_any
match_not_null
match_continuous
match_prev_avail

The character ˆ is not considered to mean ‘‘beginning of line’’
The character $ is not considered to mean ‘‘end of line’’
\b does not match the subsequence [first,first)
\b does not match the subsequence [last,last)
If more than one match is possible, then any match is acceptable
Do not match an empty sequence
Match only a subsequence that begins at first
−−first is a valid iterator position

37
...
1 regex_match()
To look for a pattern matching a whole sequence with a known length, such as a line of text, use
regex_match():

Section 37
...
1

regex_match()

1063

Regular Expression Matching (§iso
...
11
...
3)
regex_match(b,e,m,pat,flags)

Does the input [b:e) match the regex pattern pat?
place the result in match_results m; use options flags

regex_match(b,e,m,pat)
regex_match(b,e,pat,flags)
regex_match(b,e,pat)

regex_match(b,e,m,pat,regex_constants::match_default)
Does the input [b:e) match the regex pattern pat? use options flags
regex_match(b,e,pat,regex_constants::match_default)

regex_match(x,m,pat,flags)

Does the input x match the regex pattern pat?
x can be a basic_string or a C-style string;
place the result in match_results m; use options flags

regex_match(x,m,pat)
regex_match(x,pat,flags)

regex_match(x,m,pat,regex_constants::match_default)
Does the input x match the regex pattern pat?
x can be a basic_string or a C-style string; use options flags
regex_match(x,pat,regex_constants::match_default)

regex_match(x,pat)

As an example, consider a naive program for validating the format of a table
...
A table is a series of rows, each with four tab-separated fields, except for the first (title row) which may
have only three fields
...

The program reads the title line and then does the sums for each line until it reaches the final
line labeled ‘‘Total’’:
int main()
{
ifstream in("table
...
3
...
3
...
28
...
3)
Matching is controlled by match_flag_type options (§37
...
3
...
For
example, it will find strustrub in abstrustrubal
...
3
...


37
...
3 regex_replace()
To make simple substitutions of a pattern in a part of a sequence, such as a file, use regex_replace():
Regular Expression Replacement (§iso
...
11
...
3)
out=regex_replace(out,b,e,pat,fmt,flags)

Copy [b:e) to out,
searching for the regex pattern pat;
when a match for pat is found,
copy it to out using the format fmt
controlled by flags;
fmt can be a basic_string or a C-style string

out=regex_replace(out,b,e,pat,fmt)

out=regex_replace(out,b,e,pat,fmt,
regex_constants::match_defaults)
Copy x to s,
searching for the regex pattern pat;
when a match for pat is found
copy it to s using the format fmt
controlled by flags;
x can be a basic_string or a C-style string;
fmt can be a basic_string or a C-style string
s=regex_replace(x,pat,fmt,
regex_constants::match_defaults)

s=regex_replace(x,pat,fmt,flags)

s=regex_replace(x,pat,fmt)

Copying a format is done using the regex’s format() (§37
...
2) with the $ prefix notation, for example, $& for the match and $2 for the second submatch
...
By default, regex_match()
copies unmatched characters to its output, so the two spaces that were not matched by pat are
printed
...
2
...
4 Regular Expression Iterators
The regex_search() function allows us to find a single occurrence of a pattern in a data stream
...
If what we want to do with each occurrence of a pattern is a simple substitution, we can use

Section 37
...
If we want to iterate over a sequence of characters doing something for each occurrence of a pattern, we use a regex_iterator
...
4
...

}

The regex_traits are described in §37
...

The usual set of aliases is provided:
using cregex_iterator = regex_iterator;
using wcregex_iterator = regex_iterator;
using sregex_iterator = regex_iterator;
using wsregex_iterator = regex_iterator;

A regex_iterator provides a minimal set of iterator operations:
regex_iterator

(§iso
...
12
...
m
Make p point to the next occurrence

of p’s pattern

then ++p

A regex_iterator is a bidirectional iterator, so we cannot directly iterate over an istream
...
begin(),input
...
If we simplify
the pattern to R"((\ew+))", we get
aa
as
asd
e
asdf
asdfg

You cannot write through a regex_iterator and regex_iterator{} is the only possible end-of-sequence
...
4
...


The regex_traits are described in §37
...

The usual set of aliases is provided:
using cregex_token_iterator = regex_token_iterator;
using wcregex_token_iterator = regex_token_iterator;
using sregex_token_iterator = regex_token_iterator;
using wsregex_token_iterator = regex_token_iterator;

A regex_token_iterator provides a minimal set of iterator operations:

sub_matches

of the

Section 37
...
2

regex_token_iterator

regex_token_iterator
regex_token_iterator p {};
regex_token_iterator p {b,e,pat,x,flags};

regex_token_iterator p {b,e,pat,x};
regex_token_iterator p {b,e,pat};
regex_token_iterator p {q};
p
...
28
...
2)

p is the end-of-sequence
x lists the indices of the sub_matches to
included in the iteration or 0, meaning
‘‘the whole match,’’ or −1, meaning

{b,e,pat,x,regex_constants::match_default}
p is initialized with
{b,e,pat,0,regex_constants::match_default}

Copy constructor (no move constructor)
Destructor: release all resources
Copy assignment (no move assignment)
Does p point to the same sub_match as q?

q=p,
sub_matches

be

‘‘represent each character sequence not
matched as a sub_match’’;
x can be an int, an initializer_list,
a const vector&, or a const int (&sub_match)[N]
p is initialized with

!(p==q)
c is the current sub_match
x=(∗p)
...
For example (iterating over

void test1()
{
string input {"aa::bb cc::dd ee::ff"};
regex pat {R"((\w+)([[:punct:]]+)(\w+)\s∗)"};
sregex_token_iterator end {};
for (sregex_token_iterator p{input
...
end(),pat,{1,3}}; p!=end; ++p)
cout << ∗p << '\n';
}

This gives the output:
aa
bb
cc
dd
ee
ff

The −1 option basically inverts the strategy for reporting matches by representing each character
sequence that does not match as a sub_match
...
For example:
void test2()
{
string s {"1,2 , 3 ,4,5, 6 7"};
// input
regex pat {R"(\s∗,\s∗)"};
// use comma as token
copy(sregex_token_iterator{s
...
end(),pat,−1)},
sregex_token_iterator{},
ostream_iterator{cout,"\n"});
}

separator

The output is:
1
2
3
4
5
67

This could equivalently be written using an explicit loop:
void test3()
{
sregex_token_iterator end{};
for (sregex_token_iterator p {s
...
end(),pat,−1}; p!=end; ++p)
cout << ∗p << '\n';
}

37
...

};

The standard library provides specializations regex_traits and regex_traits
...
5

regex_traits

regex_traits
regex_traits tr {};
n=length(p)
c2=tr
...
translate_nocase(c)
s=tr
...
transform_primary(b,e)
s=tr
...
lookup_classname(b,e,ign)

1071

Operations (§iso
...
7)

Make a default regex_trait
n is the number of characters in the C-style string p;
n=char_traits::length(); static
c2=c, that is, a no-op
use_facet>(getloc())
...
4
...
4
...
4
...
lookup_classname(b,e)

m=tr
...
isctype(c,m)
i=tr
...
imbue(loc)
loc=tr
...

A classification name is one of the character classifications listed in §37
...
1, such as alpha, s,
and xdigit
...
6 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]
[10]
[11]

Use regex for most conventional uses of regular expressions; §37
...

The regular expression notation can be adjusted to match various standards; §37
...
1, §37
...

The default regular expression notation is that of ECMAScript; §37
...
1
...
1
...

Be restrained; regular expressions can easily become a write-only language; §37
...
1
...
1
...

Note that \i allows you to express a subpattern in terms of a previous subpattern; §37
...
1
...
1
...
2
...

regex can use ECMAScript, POSIX, awk, grep, and egrep notation; §37
...

Keep a copy of the pattern string in case you need to output it; §37
...

Use regex_search() for looking at streams of characters and regex_match() to look for fixed
layouts; §37
...
2, §37
...
1
...

– Brian W
...
1 Introduction
The I/O stream library provides formatted and unformatted buffered I/O of text and numeric values
...
; see §30
...

An ostream converts typed objects to a stream of characters (bytes):
Typed values:

Byte sequences:

'c'
123
(123,45)

‘‘Somewhere’’

ostream

stream buffer

1074

I/O Streams

Chapter 38

An istream converts a stream of characters (bytes) to typed objects:
Typed values:

Byte sequences:

'c'
123

‘‘Somewhere’’

istream

(123,45)

stream buffer

An iostream is a stream that can act as both an istream and an ostream
...
6)
...
The operations on istreams and ostreams are described in
§38
...
1 and §38
...
2
...
So I present only the general ideas needed to understand and use iostreams
...

The key components of the stream I/O system can be represented graphically like this:
ios_base:
locale independent format state

basic_streambuf<>:

buffering

real destination/source

basic_ios<>:

locale dependent format state
stream state

basic_iostream<>:
formatting (<<, >>, etc
...
’’ The dotted arrows represent ‘‘pointer to
...

The I/O stream operations:
• Are type-safe and type sensitive
• Are extensible (when someone designs a new type, matching I/O stream operators can be
added without modifying existing code)

Section 38
...
3)
• Include formatted, unformatted, and character-level operations
The basic_iostream is defined based on basic_istream (§38
...
2) and basic_ostream (§38
...
1):
template>
class basic_iostream :
public basic_istream, public basic_ostream {
public:
using char_type = C;
using int_type = typename Tr::int_type;
using pos_type = typename Tr::pos_type;
using off_type = typename Tr::off_type;
using traits_type = Tr;
explicit basic_iostream(basic_streambuf∗ sb);
virtual ˜basic_iostream();
protected:
basic_iostream(const basic_iostream& rhs) = delete;
basic_iostream(basic_iostream&& rhs);
basic_iostream& operator=(const basic_iostream& rhs) = delete;
basic_iostream& operator=(basic_iostream&& rhs);
void swap(basic_iostream& rhs);
};

The template parameters specify the character type and the traits used to manipulate characters
(§36
...
2), respectively
...
The move operations are intended for
use by derived classes and are therefore protected
...
g
...

There are three standard streams:
Standard I/O Streams
cout
cin
cerr
clog
wcin
wcout
wcerr
wclog

The standard character output (often by default a screen)
The standard character input (often by default a keyboard)
The standard character error output (unbuffered)
The standard character error output (buffered)
wistream version of cin
wostream version of cout
wostream version of cerr
wostream version of clog

Forward declarations for stream types and stream objects are provided in
...
2 The I/O Stream Hierarchy
An

istream can be connected to an input device (e
...
, a keyboard), a
ostream can be connected to an output device (e
...
, a text window or
string
...
Similarly, an
an HTML engine), a file, or a

ios_base

basic_ios<>

basic_istream<>

basic_istringstream<>

basic_ostream<>

basic_iostream<>

basic_ifstream<>

basic_fstream<>

basic_ostringstream<>

basic_ofstream<>

basic_stringstream<>

The classes suffixed by <> are templates parameterized on the character type
...
3
...

The key class is basic_ios in which most of the implementation and many of the operations are
defined
...
It is described in §38
...
4
...
g
...
4
...


38
...
1 File Streams
In , the standard library provides streams to and from a file:
• ifstreams for reading from a file
• ofstreams for writing to a file
• fstreams for reading from and writing to a file
The file streams follow a common pattern, so I describe only fstream:
template>
class basic_fstream
: public basic_iostream {
public:
using char_type = C;
using int_type = typename Tr::int_type;
using pos_type = typename Tr::pos_type;
// for positions in file
using off_type = typename Tr::off_type;
// for offsets in file
using traits_type = Tr;
//
...
2
...
swap(fs2)
p=fs
...
is_open()
fs
...
close()

(§iso
...
9)

fs is a file stream not attached to a file
fs is a file stream opened for a file called s with mode m;
s can be a string or a C-style string
Move constructor: fs2 is moved to fs; fs2 becomes unattached
Move assignment: fs2 is moved to fs; fs2 becomes unattached
Exchange the states of fs and fs2
p is a pointer to fs’s file stream buffer (basic_filebuf)
Is fs open?
Open a file called s with mode m and have fs refer to it;
sets fs’s failbit if it couldn’t open the file;
s can be a string or a C-style string
Close the file associated with fs (if any)

In addition, the string streams override the basic_ios protected virtual functions underflow(), pbackfail(), overflow(), setbuf(), seekoff(), and seekpos() (§38
...

A file stream does not have copy operations
...
6)
...
3)
...
4
...
27
...
3
...
4)
ios_base::app
ios_base::ate
ios_base::binary
ios_base::in
ios_base::out
ios_base::trunc

Append (i
...
, add to the end of the file)
‘‘At end’’ (open and seek to the end)
Binary mode; beware of system-specific behavior
For reading
For writing
Truncate the file to 0 length

In each case, the exact effect of opening a file may depend on the operating system, and if an operating system cannot honor a request to open a file in a certain way, the result will be a stream that is
in the bad() state (§38
...
For example:
ofstream ofs("target");
// ‘‘o’’ for ‘‘output’’ implying ios::out
if (!ofs)
error("couldn't open 'target' for writing");

1078

I/O Streams

Chapter 38

fstream ifs;
// ‘‘i’’ for ‘‘input’’ implying ios::in
ifs
...
6
...


38
...
2 String Streams
In , the standard library provides streams to and from a string:
• istringstreams for reading from a string
• ostringstreams for writing to a string
• stringstreams for reading from and writing to a string
The string streams follow a common pattern, so I describe only stringstream:
template, typename A = allocator>
class basic_stringstream
: public basic_iostream {
public:
using char_type = C;
using int_type = typename Tr::int_type;
using pos_type = typename Tr::pos_type;
// for positions in string
using off_type = typename Tr::off_type; // for offsets in string
using traits_type = Tr;
using allocator_type = A;
//
...
27
...
rdbuf()
s=ss
...
str(s)

stringstream ss {s,ios_base::out|ios_base::in};
Move constructor: ss2 is moved to ss; ss2 becomes empty
Move assignment: ss2 is moved to ss; ss2 becomes empty
p points to ss’s string stream buffer (a basic_stringbuf)
s is a string copy of the characters in ss: s=ss
...
rdbuf()−>str(s);
if ss’s mode is ios::ate (‘‘at end’’) values written to ss

ss
...
4
...
For an istringstream, the default mode is
For an ostringstream, the default mode is ios_base::out
...


Section 38
...
2

String Streams

1079

In addition, the string streams override the basic_ios protected virtual functions underflow(),
and seekpos() (§38
...

A string stream does not have copy operations
...

There are six string stream aliases defined in :
pbackfail(), overflow(), setbuf(), seekoff(),

using istringstream = basic_istringstream;
using wistringstream = basic_istringstream;
using ostringstream = basic_ostringstream;
using wostringstream = basic_ostringstream;
using stringstream = basic_stringstream;
using wstringstream = basic_stringstream;

For example:
void test()
{
ostringstream oss {"Label: ",ios::ate};
// write at end
cout << oss
...
str() << '\n'; // writes "Label: val" ("val" appended after "Label: ")
ostringstream oss2 {"Label: "};
// write at beginning
cout << oss2
...
str() << '\n'; // writes "valel: " (val overwrites "Label: ")
}

I tend to use str() only to read a result from an istringstream
...
str("Foobar");
cout << iss << '\n';
cout << iss
...

}
else {
// handle problem
}

1080

I/O Streams

Chapter 38

38
...
4
...
27
...
5
...
g
...
g
...
An
iostream can be used as a condition
...
That is the basis for the idiom for reading a stream of values:
for (X x; cin>>x;) { // read into an input buffer of type X
//
...

}
// we get here when >> couldn’t read another X from cin

After a read failure, we might be able to clear the stream and proceed:
int i;
if (cin>>i) {
//
...

} else if (cin
...
clear();
string s;
if (cin>>s) {
// we might be able to use a string to recover
//
...

}
}

Alternatively, errors can be handled using exceptions:
Exception Control: basic_ios (§38
...
4, §iso
...
5
...
exceptions()
ios
...
setstate(ios_base::badbit)):

throw a

st is the iostate of ios
Set ios’s iostate to st
basic_ios::failure

when its state is set to

bad()

cin
...
exceptions()|ios_base::badbit);

For example:
struct Io_guard {
// RAII class for iostream exceptions
iostream& s;
auto old_e = s
...
exceptions(s
...
exceptions(old_e); }
};

(e
...
, by a

Section 38
...
ios_base::badbit);
//
...

}
catch (ios_base::badbit) {
//
...

}

I tend to use exceptions to handle iostream errors that I don’t expect to be able to recover from
...


38
...
The description here is based on the conventional English small character set (ASCII)
...


38
...
1 Input Operations
Input operations are provided by istream (§38
...
2), found in except for the ones reading
into a string; those are found in
...

protected:
// move but no copy:
basic_istream(const basic_istream& rhs) = delete;
basic_istream(basic_istream&& rhs);
basic_istream& operator=(const basic_istream& rhs) = delete;
basic_istream& operator=(basic_istream&& rhs);
//
...
It provides common code for
standard-library and user-defined input operations
...
For example:
template>
basic_ostream& basic_ostream::operator<<(int i)
{
sentry s {∗this};
if (!s) {
// check whether all is well for output to start
setstate(failbit);
return ∗this;
}
//
...

return ∗this;
}

A sentry is used by implementers of input operations rather than by their users
...
4
...
1 Formatted Input
Formatted input is primarily supplied by the >> (‘‘input,’’ ‘‘get,’’ or ‘‘extraction’’) operator:
Formatted Input (§iso
...
7
...
2, §iso
...
4
...
9)
in>>x

getline(in,s)

Read from in into x according to x’s type; x can be an arithmetic type,
a pointer, a basic_string, a valarray, a basic_streambuf,
or any type for which the user has supplied a suitable operator>>()
Read a line from in into the string s

Built-in types are ‘‘known’’ to istream (and ostream), so if x is a built-in type, cin>>x means
cin
...
If x is a user-defined type, cin>>x, means operator>>(cin,x) (§18
...
5)
...
A designer of a new type can
provide I/O operations without direct access to the implementation of iostream
...
For example, cin>>pf yields pf(cin)
...
4
...
2)
...
4
...

Unless otherwise stated, an istream operation returns a reference to its istream, so that we can
‘‘chain’’ operations
...
setstate(ios_base::badbit);
// set badbit
throw runtime_error("bad read of pair");
}
}

Section 38
...
1
...
For example:
for (int i; cin>>i && 0cout << i << '\n';

This will take a sequence of whitespace-separated positive integers and print them one to a line
...
4
...
2)
...
That is, a user cannot do an in>>base where base is a class
hierarchy and automatically have the >> resolved to an operation on the appropriate derived class
...
4
...
1
...
2
...


38
...
1
...
One use of unformatted input is the implementation of formatted input:
Unformatted Input (§iso
...
7
...
3, §iso
...
7
...
3)
x=in
...
get(c)
in
...
get(p,n)
in
...
getline(p,n)
in
...
gcount()
in
...
unget()
in
...
ignore(n)
in
...
swap(in2)

Read one character from in and return its integer value;
return EOF for end-of-file
Read a character from in into c
Read at most n characters from in into [p:
...
get(p,n,'\n')

Read at most n characters from in into [p:
...
getline(p,n,'\n')

read at most n characters from in into [p:
...
ignore(n,traits::eof())
in
...
4
...
1) instead these low-level input functions
...
The other
get() function and getline() read sequences of characters into a fixed-size area [p:
...

They place a 0 at the end of the characters (if any) written to; getline() removes its terminator from
the input, if found, whereas get() does not
...
getline(word[i++],MAX_LINE,'\n') && i/* do nothing */ ;
//
...

• We read the maximum number of characters
...

• There was a non-format input error
...
3)
...

A read(p,n) does not write a 0 to the array after the characters read
...

The following functions depend on the detailed interaction between the stream buffer (§38
...
27
...
2
...
peek()
n=in
...
sync()
pos=in
...
seekg(pos)
in
...
);
n is the number of characters read
Synchronize buffers: in
...
4
...
6
...
4
...
4
...

protected:
// move but no copy:
basic_ostream(const basic_ostream& rhs) = delete;
basic_ostream(basic_ostream&& rhs);
basic_ostream& operator=(basic_ostream& rhs) = delete;
basic_ostream& operator=(const basic_ostream&& rhs);
//
...
6):
Output Operations (§iso
...
7
...
6, §iso
...
7
...
7, §iso
...
4
...
9)
out<
out
...
write(p,n)
out
...
tellp()
out
...
seekp(off,dir)

Write x to out according to x’s type; x can be an arithmetic type,
a pointer, a basic_string, a bitset, a complex, a valarray,
or any type for which a user has defined a suitable operator<<()
Write the character c to out
Write the characters [p:p+n) to out
Empty the character buffer to the destination
pos is the position of out’s put pointer
Place out’s put pointer at position pos
Place out’s put pointer at the offset off in the direction dir

Unless otherwise stated, an ostream operation returns a reference to its
‘‘chain’’ operations
...
For example:
void print_val(char ch)
{
cout << "the value of '" << ch << "' is " << int{ch} << '\n';
}
void test()
{
print_val('a');
print_val('A');
}

This prints:
the value of 'a' is 97
the value of 'A' is 65

1086

I/O Streams

Chapter 38

Versions of operator << for user-defined types are usually trivial to write:
template
struct Named_val {
string name;
T value;
};
ostream& operator<<(ostream& os, const Named_val& nv)
{
return os << '{' << nv
...
value << '}';
}

This will work for every Named_val where
defined for basic_string
...
For full generality,

<<

must be

38
...
2
...
The output operations that a programmer can add are not
members, so they cannot be virtual either
...
This is a place where runtime efficiency is often crucial so that inlining is a must
...
6)
...
Since the exact type isn’t known, correct output cannot be achieved simply by defining a
<< for each new type
...

virtual ostream& put(ostream& s) const = 0; // write *this to s
};
ostream& operator<<(ostream& s, const My_base& r)
{
return r
...

Given that, we can write:
class Sometype : public My_base {
public:
//
...
4
...
1

Virtual Output Functions

1087

This integrates the virtual put() into the framework provided by ostream and <<
...
This is similar to the technique that under the name double dispatch is often used to select an operation based on two dynamic types (§22
...
1)
...
2
...


38
...
3 Manipulators
If a pointer to function is given as the second argument to <<, the function pointed to is called
...
Such a function is called a manipulator
...
For example:
cout << setprecision(4) << angle;

This prints the value of the floating-point variable angle with four digits
...
precision(4) when
invoked
...
The exact
type of that function object is implementation-defined, but it might be defined like this:
struct smanip {
ios_base& (∗f)(ios_base&,int);
// function to be called
int i;
// value to be used
smanip(ios_base&(∗ff)(ios_base&,int), int ii) :f{ff}, i{ii} { }
};
template
basic_ostream& operator<<(basic_ostream& os, const smanip& m)
{
m
...
i);
// call m’s f with m’s stored value
return os;
}

We can now define setprecision() like this:
inline smanip setprecision(int n)
{
auto h = [](ios_base& s, int x) −> ios_base& { s
...
An
ios_base cannot be copied by a user
...
Doing this does not
require modification of the definitions of standard-library templates and classes
...
4
...
2
...
4
...

};

The basic_ios class manages the state of a stream:
• The mapping between a stream and its buffers (§38
...
4
...
1)
• The use of locales (Chapter 39)
• Error handling (§38
...
4
...

The ios_base holds information that does not depend on template arguments:
class ios_base {
public:
using fmtflags = /* implementation-defined type */;
using iostate = /* implementation-defined type */;
using openmode = /* implementation-defined type */;
using seekdir = /* implementation-defined type */;
class failure;
class Init;

// exception class
// initialize standard iostreams

};

The implementation-defined types are all bitmask types; that is, they support bitwise logical operations, such as & and |
...
1
...
2
...

The ios_base controls an iostream’s connection (or lack thereof) to stdio (§43
...
27
...
3
...
˜ios_base()

A call of

sync_with_stdio(true)

before the first

iostream

operation in the execution of a program

Section 38
...
4

Stream State

1089

guarantees that the

iostream and stdio (§43
...
A call of
before the first stream I/O operation prevents buffer sharing and can improve
I/O performance significantly on some implementations
...


sync_with_stdio(false)

ios_base
badbit
failbit
eofbit
goodbit

Stream State iostate Member Constants (§iso
...
5
...
1
...
g
...
g
...
g
...
) in a stream are provided by basic_ios
...
27
...
3
...
4)
Append (insert output at end-of-stream)
At end (position to end-of-stream)
Don’t apply formatting to characters
Input stream
Output stream
Truncate stream before use (set the stream’s size to zero)

The exact meaning of ios_base::binary is implementation-dependent
...
For example:
template
char∗ as_bytes(T& i)
{
return static_cast(&i); // treat that memory as bytes
}
void test()
{
ifstream ifs("source",ios_base::binary);
ofstream ofs("target",ios_base::binary);

// stream mode is binary
// stream mode is binary

vector v;
for (int i; ifs
...
push_back(i);

// read bytes from binary file

//
...

for (auto i : v)
ofs
...
Images and sound/video streams are examples
...
6
...
6
...
27
...
3
...
5)

beg
cur
end

Seek from beginning of current file
Seek from current position
Seek backward from end of current file

Classes derived from basic_ios format output and extract objects based on the information stored in
their basic_io
...
27
...
5)

basic_ios ios {p};
ios
...
fail(); explicit

b=!ios
st=ios
...
clear(st)
ios
...
setstate(st)
ios
...
eof()
ios
...
fail()
st is the iostate of ios
Set the iostate of ios to st
Set the iostate of ios to good
Add st to ios’s iostate
Is the state of ios good (is goodbit
Is the state of ios end-of-file?
Is the state of ios fail?

ios
...
exceptions()
ios
...
tie()
p=ios
...
pword and ios2
...
rdbuf()
p=ios
...
copyfmt(ios2)

c=ios
...
fill(c)
loc2=ios
...
narrow(c,d))

Section 38
...
4

Stream State

basic_ios
c2=widen(c)
ios
...
set_rdbuf(p)
ios
...
swap(ios2)

1091

(continued) (§iso
...
5
...
widen(c))
Set ios to the default state and use the stream buffer pointed to
Make ios use the stream buffer pointed to by p; protected

by p; protected

Copy and move operation; protected
Exchange the states of ios and ios2; protected; noexcept

The conversion of an ios (including istreams and ostreams) to bool is essential to the usual idiom for
reading many values:
for (X x; cin>>x;) {
//
...
This ios is implicitly converted to a bool
representing the state of cin
...
fail();) {
//
...
For example, cout is tied to cin:
cout << "Please enter a number: ";
int num;
cin >> num;

This code does not explicitly call
the request for input
...
flush(),

so had

cout

not been tied to

cin,

the user would see

Operations (§iso
...
5
...
5, §iso
...
5
...
6)

i=xalloc()
r=iob
...
pword(i)
iob
...
For example, one might want a stream to
‘‘know’’ whether a complex should be output in polar or Cartesian coordinates
...
The value returned by
xalloc() identifies a pair of locations that can be accessed by iword() and pword()
...

The register_callback() function ‘‘registers’’ a function to be called when its ‘‘event’’ occurs
...
When the state changes, registered functions are called with
the argument i supplied by their register_callback()
...
4
...
4
...
4
...
1), locale information (Chapter 39), and explicit operations (e
...
, manipulators;
§38
...
5
...


38
...
5
...
27
...
3
...
2)

Use symbolic representation of true and false
Integer base is 10
Integer base is 16
Integer base is 8
Floating-point format dddd
...
ddddEdd
Pad between a prefix (such as +) and the number
Pad after the value
Pad before the value
On output, prefix octal numbers by 0
and hexadecimal numbers by 0x
Always show the decimal point (e
...
, 123
...
g
...
g
...
2E10 and 0X1A2
Set a value’s placement in its field: left, right, or internal
Set the integer’s base: dec, oct, or hex
Set the floating-point format: scientific or fixed

Curiously, there are no defaultfloat or hexfloat flags
...
4
...
2), or manipulate the ios_base directly:

float

ios
...
setf(ios_base::fixed | ios_base::scientific, ios_base::floatfield);
// use hexadecimal floats

An iostream’s format state can be read and written (set) by operations provided in its ios_base:

Section 38
...
5
...
flags()
f2=ios
...
setf(f)
f2=ios
...
unsetf(f)
n=ios
...
precision(n)
n=ios
...
width(n)

1093

Formatting fmtflags Operations (§iso
...
5
...
2)
is ios’s formatting flags
Set ios’s formatting flags to f; f2 is the old value of the flags
Set ios’s formatting flags to f; f2 is the old value of the flags

f

f2=ios
...
The precision specifies
the maximum number of digits
...
The precision specifies the maximum number of digits after the decimal point
...
The precision specifies the maximum number of digits after the decimal
point
...
4
...
2
...
For example:
cout
...
56789 << ' ' << 1234
...
precision(4);
cout << 1234
...
56789 << ' ' << 123456 << '\n';

This produces:
1234
...
5679 123456
1235 1235 123456

The width() function specifies the minimum number of characters to be used for the next standardlibrary << output operation of a numeric value, bool, C-style string, character, pointer, string, and
bitset (§34
...
2)
...
width(4);
cout << 12;
// print 12 preceded by two spaces

The ‘‘padding’’ or ‘‘filler’’ character can be specified by the fill() function
...
width(4);
cout
...
’’ The field size can be reset to its default value like this:

1094

I/O Streams

Chapter 38

cout
...
If more characters are provided, they
will all be printed
...
width(4);
cout << "abcdef";

// print abcdef

It does not truncate the output to abcd
...

A width(n) call affects only the immediately following << output operation
...
width(4);
cout
...

If the explicit control of formatting options through many separate operations becomes tedious,
we can combine them using a user-defined manipulator (§38
...
5
...

An ios_base also allows the programmer to set an iostream’s locale (Chapter 39):
ios_base locale
loc2=ios
...
getloc()

Operations (§iso
...
5
...
3)

Set ios’s locale to loc; loc2 is the old value of the locale
loc is ios’s locale

38
...
5
...
The standard manipulators are defined in , , , and (for
manipulators that take arguments):
I/O Manipulators from (§iso
...
5
...
27
...
4) (continues)
s<s<s<
Use symbolic representation of true and false (input and output)

s<s<s<s<s<s<s<s<s<
s
...
unsetf(ios_base::boolalpha)

On output prefix octal numbers by 0
and hexadecimal numbers by 0x
Always show decimal point
s
...
unsetf(ios_base::showpos)

Use uppercase in numeric output, e
...
, 1
...
g
...
2e10 and 0x1a2
Flush after each output operation
Do not flush after each output operation

Section 38
...
5
...
27
...
6, §iso
...
7
...
dd
Scientific format d
...
g
...
1BEp−C and a
...
unsetf(ios_base::skipws)

Each of these operations returns a reference to its first (stream) operand, s
...
456;
cout << d << "; "
<< scientific << d << "; "
<< hexfloat << d << "; "
<< fixed << d << "; "
<< defaultfloat << d << '\n';

This produces:
123
...
234560e+002; 0x1
...
456000; 123
...

I/O Manipulators from (§iso
...
5
...
27
...
4)
os<os<os<<flush

Put '\n' and flush
Put '\0'
Flush stream

An ostream is flushed when it is destroyed, when a tie()d istream needs input (§38
...
4), and when
the implementation finds it advantageous
...

Similarly, < ...


1096

I/O Streams

Chapter 38

I/O Manipulators from (§iso
...
5
...
27
...
4)
s<s<s<s<s<s<is>>get_money(m,intl)

is>>get_money(m)
os<
Clear flags f
Set flags f
Output integers in base b
Make c the fill character
Precision is n digits
Next field width is n char
Read from is using is’s money_get facet;
m is a long double or a basic_string;
if intl==true, use standard three-letter currency names
s>>get_money(m,false)

Write m to os using os’s money_put facet;
that money_put determines which types are acceptable for m;
if intl==true, use standard three-letter currency names

os<
s<
is>>get_time(tmp,fmt)

Read into ∗tm according to the format fmt,
using is’s time_get facet
Write ∗tm to os according to the format fmt,
using os’s time_put facet

os<
The time facets are found in §39
...
4 and the time formats in §43
...

For example:
cout << '(' << setw(4) << setfill('#') << 12 << ") (" << 12 << ")\n";
istream

Manipulators (§iso
...
5
...
27
...
4)

s>>skipws
s>>noskipws
is>>ws

By default
>>noskipws
...
unsetf(ios_base::skipws) (in )
Eat whitespace (in )

skips whitespace (§38
...
1)
...
4
...
2

Standard Manipulators

1097

If you want to explicitly deal with whitespace (e
...
, to make a newline significant) and still use >>,
noskipws and >>ws become a convenience
...
4
...
3 User-Defined Manipulators
A programmer can add manipulators in the style of the standard ones
...

Formatting is controlled by a confusing multitude of separate functions (§38
...
5
...
For example, a precision() persists for all output operations, but a width() applies to the next numeric output
operation only
...
The basic idea is to
define a class that represents formats, another that represents a format plus a value to be formatted,
and then an operator << that outputs the value to an ostream according to the format
...
scientific()
...
56789) writes:
1234
...
23456789e+003 1234
...
57 1235 1
...
57

Note how the use of a Form doesn’t affect the state of the stream, so that the last output of d has the
same default format as the first
...


// precision
// width 0 means ‘‘as wide as necessary’’
// general, scientific, or fixed (§38
...
5
...


// explicit plus
// print trailing zeros

};

The idea is that a Form holds all the information needed to format one data item
...
The () operator is used to bind a value with the format to be used to
output it
...
2
...
precision(bf
...
prc);
s
...
f
...
val;
// compose string in s
return os << s
...

Note that these declarations make the combination of << and () into a ternary operator;
cout<real computation
...
5 Stream Iterators
In , the standard library provides iterators to allow input and output streams to be viewed
as sequences [input-begin:end-of-input) and [output-begin:end-of-output):

Section 38
...

};
template>
class ostream_iterator: public iterator {
using char_type = C;
using traits_type = Tr;
using ostream_type = basic_ostream;
//
...
So, if you enter 1 2 3 to that call of copy(), the output is:
1;
2;
3;

The operators provided for a stream_iterator are the same as for other iterator adaptors (§33
...
2):
Stream Iterator Operations (§iso
...
6)
istream_iterator p {st};
istream_iterator p {p2};
ostream_iterator p {st};
ostream_iterator p {p2};
ostream_iterator p {st,s};
p=p2
p2=++p
p2=p++
∗p=x
∗p++=x

Iterator for input stream st
Copy constructor: p is a copy of the istream_iterator p2
Iterator for output stream st
Copy constructor: p is a copy of the ostream_iterator p2
Iterator for output stream st; use the C-style string s
as the separator between output elements
p is a copy of p2
p and p2 point to the next element
p2=p,++p

Insert x before p
Insert x before p, then increment p

Except for the constructors, these operations are typically used by general algorithms, such as
copy(), rather than directly
...
6 Buffering
Conceptually, an output stream puts characters into a buffer
...
Such a buffer is called a streambuf
...
Different types of streambufs implement different
buffering strategies
...
Thus, an ostream can be represented graphically
like this:

ostream:

real destination
tellp()
streambuf:

begin
current
end

locale:

character buffer
The set of template arguments for an ostream and its streambuf must be the same, and they determine the type of character used in the character buffer
...

Unbuffered I/O is simply I/O where the streambuf immediately transfers each character, rather
than holding on to characters until enough have been gathered for efficient transfer
...

virtual ˜basic_streambuf();
};

As usual, a couple of aliases are provided for the (supposedly) most common cases:
using streambuf = basic_streambuf;
using wstreambuf = basic_streambuf;

The basic_streambuf has a host of operations
...
6

Buffering

public basic_streambuf
sb
...
getloc()
loc2=sb
...
pubsetbuf(s,n)
pos=sb
...
pubseekoff(n,w)
pos=sb
...
pubseekpos(n)
sb
...
27
...
3)

Destructor: release all resources; virtual
loc is sb’s locale
sb
...
setbuf(s,n)
pos=sb
...
seekoff(n,w)
pos=sb
...
seekpos(n,ios_base::in|ios_base::out)
sb
...

protected basic_streambuf

Operations (§iso
...
6
...
swap(sb2)
sb
...
setbuf(s,n)

Exchange the states of sb and sb2
loc becomes sb’s locale; virtual
Set sb’s buffer; psb=&sb;
s is a const char∗ and n is a streamsize; virtual
Seek with an offset n, a direction w, and a mode m;
pos is the resulting position or pos_type(off_type(−1)),
indicating an error; virtual

pos=sb
...
seekoff(n,w)
pos=sb
...
sync()

locale

pos=sb
...

A streambuf has a put area into which << and other output operations write (§38
...
2), and a get
area from which >> and other input operations read (§38
...
1)
...

For a use of positioning, see §38
...
1
...
27
...
3) (continues)

n=sb
...
snextc()
n=sb
...
sgetc()
n=sb
...
sputbackc(c)

n=sb
...
sputc(c)

n=sb
...
egptr()−sb
...
showmanyc()
Increase sb’s get pointer, then c=∗sb
...
underflow();
otherwise c=∗sb
...
xsgetn(p,n); p is a char∗
Put c back into the get area and decrease the gptr;
n=Tr::to_int_type(∗sb
...
pbackfail(Tr::to_int_type(c))
Decrease the get pointer;
n=Tr::to_int_type(∗sb
...
pbackfail(Tr::to_int_type())
If there is no character left to put into,
n=sb
...
sptr()=c; n=Tr::to_int_type(c)
n=sb
...
In addition, there are virtual functions to be overridden by derived classes
...
27
...
3)

sb
...
eback()
pc=sb
...
egptr()
sb
...
showmanyc()

n=sb
...
uflow()
n=sb
...
pbackfail()

The get area is [b,e); the current get pointer is n
[pc:sb
...
eback():pc) is the get area
Increase sb’s get pointer
‘‘Show how many characters’’; n is an estimate of how many
characters can be read without calling sb
...
underflow(), but advance the get pointer after reading
the new current get character; virtual
A putback operation failed; n=Tr::eof() if an overriding
pbackfail() could not put back; virtual
n=sb
...
6

protected

Buffering

1103

Put and Get basic_streambuf Operations (continued) (§iso
...
6
...
setp(b,e)
pc=sb
...
pptr()
pc=sb
...
pbump(n)
n2=sb
...
xsputn(s,n)
n=sb
...
overflow()

The put area is [b,e) the current put pointer is b
[pc:sb
...
pbase(),pc) is the put area
Add one to the put pointer
s is a const char∗; do sb
...
sputc(∗p) for each p in [s:s+n);
n2 is the number of character written; virtual
Replenish the put area, then n=sb
...
overflow(Tr::eof())

The showmanyc() (‘‘show how many characters’’) function is an odd function intended to allow a
user to learn something about the state of a machine’s input system
...
A call to showmanyc() returns −1 if it cannot promise that any character can
be read without encountering end-of-file
...
Don’t use showmanyc() without a careful reading of your system documentation and conducting a few experiments
...
6
...
4
...
4
...
In addition, an
ostream provides operations that deal directly with its streambuf:
template>
class basic_ostream : virtual public basic_ios {
public:
//
...

An ostream is constructed with a streambuf argument, which determines how the characters
written are handled and where they eventually go
...
2
...
2
...
6)
...
The p suffix indicates that it
is the position used for putting characters into the stream
...
The pos_type
represents a character position in a file, and the off_type represents an offset from a point indicated
by an ios_base::seekdir
...
For example:
int f(ofstream& fout)// fout refers to some file
{
fout << "0123456789";
fout
...
seekp(−4,ios_base::cur);
// 4 backward
fout << '∗';
// add '*' and move position (+1)
}

If the file was initially empty, we get:
01234∗67#9

There is no similar way to do random access on elements of a plain istream or ostream
...
4
...
However, some operating systems have operating modes where the behavior differs
(e
...
, positioning might resize a file)
...

It is possible to use << to write a streambuf directly into an ostream
...


38
...
2 Input Streams and Buffers
An istream provides operations for reading characters and converting them into values of various
types (§38
...
1)
...

explicit basic_istream(basic_streambuf∗ b);
pos_type tellg();
basic_istream& seekg(pos_type);
basic_istream& seekg(off_type, ios_base::seekdir);

// get current position
// set current position
// set current position

basic_istream& putback(C c);
basic_istream& unget();
int_type peek();

// put c back into the buffer
// put back most recent char read
// look at next character to be read

int sync();

// clear buffer (flush)

basic_istream& operator>>(basic_streambuf∗ b);
// read into b
basic_istream& get(basic_streambuf& b, C t = Tr::newline());

Section 38
...
2

streamsize readsome(C∗ p, streamsize n);

Input Streams and Buffers

1105

// read at most n char

};

The basic_istream functions override their equivalents in the basic_istream’s basic_ios base
...
6
...
The g suffix indicates
that it is the position used for getting characters from the stream
...

The putback() function allows a program to put a character ‘‘back’’ into an istream to be the next
character read
...
Unfortunately,
backing up an input stream is not always possible
...
What is guaranteed is that you can back up one character
after a successful read
...
Thus, c=peek() is logically equivalent to
(c=get(),unget(),c)
...
3)
...
This cannot always be done right
...
g
...
Consequently, sync() returns 0 if it succeeded
...
4
...
Setting badbit might trigger an
exception (§38
...
A sync() on a buffer attached to an ostream flushes the buffer to output
...

The readsome() function is a low-level operation that allows a user to peek at a stream to see if
there are any characters available to read
...
See also in_avail() (§38
...


38
...
3 Buffer Iterators
In , the standard library provides istreambuf_iterator and ostreambuf_iterator to allow a user
(mostly an implementer of a new kind of iostream) to iterate over the contents of a stream buffer
...


38
...
3
...
24
...
3
class istreambuf_iterator
:public iterator {
public:
using char_type = C;
using traits_type = Tr;
using int_type = typename Tr::int_type;
using streambuf_type = basic_streambuf;
using istream_type = basic_istream;
//
...

If you use an istreambuf_iterator as an input iterator, its effect is like that of other input iterators:
a stream of characters can be read from input using c=∗p++:
istreambuf_iterator
istreambuf_iterator p {};
istreambuf_iterator p {p2};
istreambuf_iterator p {is};
istreambuf_iterator p {psb};
istreambuf_iterator p {nullptr};
istreambuf_iterator p {prox};
p
...
equal(p2)
p==p2
p!=p2

(§iso
...
6
...
rdbuf(); noexcept
p is an iterator to the istreambuf ∗psb; noexcept
p is an end-of-stream iterator
p points to the istreambuf designated by prox; noexcept
Destructor
c is the character returned by the streambuf’s sgetc()
The member m of ∗p, if that is a class object
The streambuf’s sbumpc()
Let prox designate the same position as p; then ++p
Are both p and p2, or neither, at end-of-stream
p

p
...
equal(p2)

Note that any attempt to be clever when comparing istreambuf_iterators will fail: you cannot rely on
two iterators referring to the same character while input is going on
...
6
...
2 ostreambuf_iterator
An ostreambuf_iterator writes a stream of characters to an ostream_buffer:
template> // §iso
...
6
...

};

By most measures, ostreambuf_iterator’s operations are odd, but the net effect is that if you use it as
an output iterator, its effect is like that of other output iterators: a stream of characters can be written to output using ∗p++=c:
ostreambuf_iterator
ostreambuf_iterator p {os};
ostreambuf_iterator p {psb};

p
p

(§iso
...
6
...
rdbuf(); noexcept
is an iterator for the istreambuf ∗psb; noexcept

Section 38
...
3
...
failed()

1107

(continued) (§iso
...
6
...
failed() call the streambuf’s sputc(c)
Do nothing
Do nothing
Do nothing
Has a sputc() on p’s streambuf reached eof? noexcept

38
...
1, §38
...
1, §38
...
2
...
1
...
1
...
2
...
2
...

Binary I/O is system specific; §38
...
1
...
2
...

Prefer ifstreams and ofstreams over the generic fstream; §38
...
1
...
2
...

Use exceptions to catch rare bad() I/O errors; §38
...

Use the stream state fail to handle potentially recoverable I/O errors; §38
...

You don’t need to modify istream or ostream to add new << and >> operators; §38
...
1
...
4
...

Prefer formatted input over unformatted, low-level input; §38
...
1
...
4
...

Be careful with the termination criteria when using get(), getline(), and read(); §38
...
1
...
4
...

You can define a << (or a >>) so that it behaves as a virtual function based on its second operand; §38
...
2
...

Prefer manipulators to state flags for controlling I/O; §38
...
3
...
4
...

Use sync_with_stdio(false) to optimize iostreams; §38
...
4
...
4
...

Use imbue() to make an iostream reflect ‘‘cultural differences’’ of a locale; §38
...
4
...
4
...
1
...
4
...
1
...
g
...
4
...
2
...
4
...
2
...
4
...
2
...
4
...
2
...
4
...
3
...
4
...
3
...

– Proverb









Handling Cultural Differences
Class locale
Named locales; Comparing strings
Class facet
Accessing facets in a locale; A Simple User-defined facet; Uses of locales and facets
Standard facets
string Comparison; Numeric Formatting; Money Formatting; Date and Time Formatting;
Character Classification; Character Code Conversion; Messages
Convenience Interfaces
Character Classifications; Character Conversions; String Conversions; Buffer Conversions
Advice

39
...
The notion of a locale is extensible so that a programmer can add new facets to a locale
representing locale-specific entities not directly supported by the standard library, such as postal
codes (zip codes) and phone numbers
...

This chapter describes how to use a locale, how a locale is constructed out of facets, and how a
locale affects an I/O stream
...
Most operating systems and application
environments have a notion of locale
...
Thus, the C++
standard-library notion of a locale can be seen as a standard and portable way for C++ programs to
access information that has very different representations on different systems
...

Consider writing a program that needs to be used in several countries
...
Many of
the entities that a program manipulates will conventionally be displayed differently in those countries
...
For example:
void print_date(const Date& d)
// print in the appropriate format
{
switch(where_am_I) {
// user-defined style indicator
case DK:
// e
...
, 7
...
day() << "
...
month()] << " " << d
...
g
...
year() << " − " << d
...
day();
break;
case US:
// e
...
, 3/7/1999
cout << d
...
day() << "/" << d
...

}
}

This style of code does the job
...
In particular, we
have to use this style consistently to ensure that all output is properly adjusted to local conventions
...
Worse yet,
writing dates is only one of many examples of cultural differences
...

The iostream library relies on this framework to handle both built-in and user-defined types (§38
...

For example, consider a simple loop copying (Date,double) pairs that might represent a series of
measurements or a set of transactions:
void cpy(istream& is, ostream& os) // copy (Date,double) stream
{
Date d;
double volume;
while (is >> d >> volume)
os << d << ' '<< volume << '\n';
}

Naturally, a real program would do something with the records and ideally also be a bit more careful about error handling
...
1

Handling Cultural Differences

12,5 means twelve and a
locales and I/O operations

1111

half) and write it according to American conventions? We can define
so that cpy() can be used to convert between conventions:

void f(istream& fin, ostream& fout, istream& fin2, ostream& fout2)
{
fin
...
UTF−8"});
// American English
fout
...
UTF−8"});
// French
cpy(fin,fout);
// read American English, write French
//
...
imbue(locale{"fr_FR
...
imbue(locale{"en_US
...


// French
// American English
// read French, write American English

}

Given these streams:
Apr 12, 1999
Apr 13, 1999
Apr 14, 1999

...


1000
...
45
9688
...

July 3, 1950 10
...
45
July 3, 1952 67
...


Much of the rest of this chapter is devoted to describing the mechanisms that make this possible
and explaining how to use them
...
At most, they will simply
retrieve a standard locale and imbue a stream with it (§38
...
5
...

The concept of localization (internationalization) is simple
...
Such conventions vary in many subtle and unsystematic ways
...

[2] The concept of a locale must be extensible, because it is not possible to enumerate every
cultural convention that is important to every C++ user
...
g
...

[4] A locale must be invisible to the majority of programmers who want to benefit from facilities ‘‘doing the right thing’’ without having to know exactly what ‘‘the right thing’’ is or
how it is achieved
...

The mechanisms provided to compose those locales and to make them trivial to use constitute a little programming language of their own
...
4
...
4
...
A facet is an object of a class derived from class
locale::facet (§39
...
We can think of a locale as a container of facets (§39
...
3
...


39
...

locale
locale loc {};
locale loc {loc2};
locale loc {s};
locale loc {loc2,s,cat};

locale loc {loc2,pf};
locale loc {loc2,loc3,cat};

loc
...
combine(loc2)
s=loc
...
22
...
1)

is a copy of the current global locale; noexcept
Copy constructor: loc holds a copy of loc2;
loc
...
name(); noexcept
Initialize loc to the locale with the name s;
s can be a string or a C-style string; loc
...
2

Class locale

1113

If a locale of a given name or a facet referred to doesn’t exist, the locale operation naming it throws
a runtime_error
...
When you make a new locale from another plus a facet and
the resulting locale has a name, that name is implementation-defined
...
For a locale
without a name, name() returns "∗"
...
A real implementation of locale is an efficient variant of this idea
...

numpunct:
decimal_point()
truename()


...
4)
...

A locale is meant to be copied freely and cheaply
...
The facets must be quickly accessible in a locale
...
The facets of a locale are
accessed by using the use_facet(loc) notation; see §39
...
1
...
To help the programmer manipulate facets in
logical groups, the standard facets are grouped into categories, such as numeric and collate (§39
...
22
...
1)

E
...
, collate; §39
...
1
E
...
, ctype; §39
...
5
E
...
, num_put, num_get, numpunct; §39
...
2
money_put, money_get, moneypunct; §39
...
3
E
...
, time_put, time_get; §39
...
4
messages; §39
...
7
collate | ctype | monetary | numeric | time | messages

There are no facilities for a programmer to specify a name string for a newly created locale
...


1114

Locales

Chapter 39

A programmer can replace facets from existing categories (§39
...
4
...
1)
...
The notion of ‘‘category’’ applies to standardlibrary facets only, and it is not extensible
...

If a locale x does not have a name string, it is undefined whether locale::global(x) affects the C
global locale
...
There is no standard way for a C program to set the C++ global locale (except by calling a C++ function to do so)
...

By far the dominant use of locales is implicitly, in stream I/O
...
The locale of a stream is by default the global locale (§39
...
1) at the time of the
stream’s creation
...
4
...
1)
...


39
...
1 Named locales
A locale is constructed from another locale and from facets
...
For example:
locale loc1;
locale loc2 {""};

// copy of the current global locale
// copy of ‘‘the user’s preferred locale’’

locale loc3 {"C"};
locale loc4 {locale::classic()};

// copy of the ‘‘C’’ locale
// copy of the ‘‘C’’ locale

locale loc5 {"POSIX"};
locale loc6 {"Danish_Denmark
...
UTF−8"};

// copy of the locale named "POSIX"
// copy of the locale named "Danish_Denmark
...
UTF-8"

The meaning of locale{"C"} is defined by the standard to be the ‘‘classic’’ C locale; this is the locale
that has been used throughout this book
...

The locale{""} is deemed to be ‘‘the user’s preferred locale
...
So to see your current ‘‘preferred locale,’’ write:
locale loc("");
cout << loc
...
1252

On my Linux box, I got:
en_US
...
Instead, a variety of organizations, such as
POSIX and Microsoft, maintain their own (differing) standards across different programming languages
...
2
...
utf8
de_DE
...
S
...

French for Canada
German for Germany
German for Germany with the euro symbol €
German for Germany using UTF-8
German for Germany using UTF-8 with the euro symbol €

POSIX recommends a format of a lowercase language name, optionally followed by an uppercase
country name, optionally followed by an encoding specifier, for example, sv_FI@euro (Swedish for
Finland including the euro symbol)
...
1256
Basque
...
1252
Chinese_Singapore
...
1252
English_United States
...
1252
Greek_Greece
...
1255
Hindi_India
...
1251

Microsoft uses a language name followed by a country name optionally followed by a code page
number
...

Most operating systems have ways of setting a default locale for a program
...
Often, a
locale suitable to the person using a system is chosen when that person first encounters a system
...
However, these names are not standardized across platforms
...

It is generally a good idea to avoid embedding locale name strings in the program text
...
Mentioning a locale name string has similar unpleasant consequences
...
Alternatively, a program can request a user to specify alternative locales by entering
a string
...
g
...
A function implementing
this would need to know where and how a system keeps its locales
...

If the string argument doesn’t refer to a defined locale, the constructor throws the runtime_error
exception (§30
...
1
...
For example:
void set_loc(locale& loc, const char∗ name)
try
{
loc = locale{name};
}
catch (runtime_error&) {
cerr << "locale
//
...
If not, name() will return string("∗")
...
Secondarily, a
name string can be used as a debugging aid
...
name() << "\n";
cout << "name of classic C locale: " << locale::classic()
...
name() << "\n";
cout << "name of my locale: " << my_loc
...
2
...
1 Constructing New locales
A new locale is made by taking an existing locale and adding or replacing
locale is a minor variation on an existing one
...


Typically, a new

void f(const locale& loc, const My_money_io∗ mio)
// My_money_io defined in §39
...
3
...

}

Section 39
...
1
...
4
...
Similarly,
loc2 is a copy of the C locale modified to use a My_money_io (§39
...
3
...
The resulting locales can
be represented like this:
collate:
classic():
loc2:
compare()
hash()


...

My_money_io:
decimal_point()
curr_symbol()


...

In a construction locale{loc,f}, the f argument must identify a specific facet type
...
For example:
Facet∗

locale

void g(const locale::facet∗ mio1, const money_put∗ mio2)
{
locale loc3 = locale(locale::classic(), mio1);
// error : type of facet not known
locale loc4 = locale(locale::classic(), mio2);
// OK: type of facet known (moneyput)
//
...

Specifically, the implementation of locale uses a facet’s identifying type, facet::id (§39
...
3
...
The constructor
template locale(const locale& x, Facet∗ f);

is the only mechanism offered within the language for the programmer to supply a facet to be used
through a locale
...
2
...
Named
locales can be retrieved from the program’s execution environment
...

The set of constructors for locale is designed so that the type of every facet is known either from
type deduction (of the Facet template parameter) or because it came from another locale (that knew
its type)
...
This implies that the locale class can (and does) keep
track of the types of facets so that it can manipulate them with minimal overhead
...
3)
...
Instead, the locale operations provide ways of making
new locales from existing ones
...
This allows someone using a locale to call virtual functions of a
facet and to cache the values returned
...
4
...
Only a call of imbue() for the
stream (§38
...
5
...


39
...
2 Comparing strings
Comparing two strings according to a locale is possibly the most common use of a locale outside
I/O
...
4
...
This string comparison function is
defined as locale’s operator()()
...

}
}

Having the comparison function as the
For example:

()

operator makes it directly useful as a predicate (§4
...
4)
...
begin(),v
...

sort(v
...
end(),my_locale); // sor t according to the rules of my_locale
//
...
6, §31
...
2
...


39
...
A facet represents one specific cultural aspect, such as how a
number is represented on output (num_put), how a date is read from input (time_get), and how characters are stored in a file (codecvt)
...
4
...
3
...

A facet is represented in a program as an object of a class derived from std::locale::facet
...
3

Class facet

1119

class locale::facet {
protected:
explicit facet(size_t refs = 0);
virtual ˜facet();
facet(const facet&) = delete;
void operator=(const facet&) = delete;
};

The facet class is designed to be a base class
tected to prevent the creation of ‘‘plain facet’’

and has no public functions
...

A facet is intended to be managed through pointers stored in locales
...
Conversely, a nonzero constructor argument ensures that locale never deletes the facet
...

Each kind of facet interface must have a separate id:
class locale::id {
public:
id();
void operator=(const id&) = delete;
id(const id&) = delete;
};

The intended use of id is for the user to define a static member of type id of each class supplying a
new facet interface (for example, see §39
...
1)
...
2, §39
...
1)
...

Data used to define a (derived) facet is defined in the derived class
...

A facet is intended to be immutable, so all member functions of a user-defined facet should be
defined const
...
3
...
22
...
2)
f=use_facet(loc)
has_facet(loc)

f is a reference to the facet F in loc; throw bad_cast if loc doesn’t have F
Does loc have facet F? noexcept

Think of these functions as doing a lookup in their locale argument for their template parameter F
...
This is feasible because a locale can have only one facet of a given type
...
decimal_point() // use standard facet
//
...
get_crypto();
// use Encrypt facet
//
...

}

The standard facets are guaranteed to be available for all locales (§39
...

One way of looking at the facet::id mechanism is as an optimized implementation of a form of
compile-time polymorphism
...
However, the specialized use_facet can be implemented more efficiently than
the general dynamic_cast
...
That is, if two facet classes have
exactly the same interface and implement the same semantics (as far as a locale is concerned), they
should be identified by the same id
...
4
...

If we define a facet with a new interface – such as Encrypt in f() – we must define a corresponding id to identify it (see §39
...
2 and §39
...
1)
...
3
...
To examine the facet mechanism in isolation from the complexities of widely used types and the efficiency concerns that accompany them, let me first present
a facet for a trivial user-defined type:
enum Season { spring, summer, fall, winter }; // very simple user-defined type

The style of I/O outlined here can be used with little variation for most simple user-defined types
...
3)
virtual const string& to_str(Season x) const = 0;
// string representation of x
virtual bool from_str(const string& s, Season& x) const = 0; // place Season for s in x
static locale::id id; // facet identifier object (§39
...
3, §39
...
1)
};
locale::id Season_io::id; // define the identifier object

Section 39
...
2

A Simple User-Defined facet

1121

For simplicity, this facet is limited to strings of chars
...
To define
the I/O representation of a Season for a particular locale, we derive a class from Season_io, defining
to_str() and from_str() appropriately
...
If the stream has a Season_io facet, we can use that to convert the
value into a string
...
getloc()};
// extract the stream’s locale (§38
...
4)
if (has_facet(loc))
return os << use_facet(loc)
...
4
...
2, §39
...
2
...
However, for a simple user-defined type, such as Season, there is no need to
drop to the streambuf level of abstraction
...
getloc()};

// extract the stream’s locale (§38
...
4)

if (has_facet(loc)) {
const Season_io& f {use_facet(loc)}; // get hold of the locale’s Season_io facet
string buf;
if (!(is>>buf && f
...
setstate(ios_base::failbit);
return is;

// read alphabetic representation

}
int i;
is >> i;
x = static_cast(i);
return is;

// read numeric representation

}

The error handling is simple and follows the error-handling style for built-in types
...
If
exceptions are enabled, this implies that an ios_base::failure exception is thrown (§38
...

Here is a trivial test program:
int main()
// a trivial test
{
Season x;

1122

Locales

Chapter 39

// use the default locale (no Season_io facet) implies integer I/O:
cin >> x;
cout << x << endl;
locale loc(locale(),new US_season_io{});
cout
...
imbue(loc);
// use locale with Season_io facet
cin >> x;
cout << x << endl;
}

Given the input
2
summer

this program responds:
2
summer

To get this, we must derive a class
representation of the seasons:

US_season_io

from

Season_io,

and define an appropriate string

class US_season_io : public Season_io {
static const string seasons[];
public:
const string& to_str(Season) const;
bool from_str(const string&, Season&) const;
// note: no US_season_io::id
};
const string US_season_io::seasons[] = {
"spring",
"summer",
"fall",
"winter"
};

Then, we override the
enumerators:

Season_io

functions that convert between the string representation and the

const string& US_season_io::to_str(Season x) const
{
if (xstatic const string ss = "no−such−season";
return ss;
}
return seasons[x];
}

Section 39
...
2

A Simple User-Defined facet

1123

bool US_season_io::from_str(const string& s, Season& x) const
{
const string∗ p = find(begin(seasons),end(seasons),s);
if (p==end)
return false;
x = Season(p−begin(seasons));
return true;
}

Note that because US_season_io is simply an implementation of the Season_io interface, I did not
define an id for US_season_io
...
Operations on locales, such as has_facet (§39
...
1), rely on facets
implementing the same concepts being identified by the same id (§39
...

The only interesting implementation question is what to do if asked to output an invalid Season
...
However, it is not uncommon to find an invalid value for a simple
user-defined type, so it is realistic to take that possibility into account
...
Note that for input, the errorhandling policy is left to the >> operator, whereas for output, the facet function to_str() implements
an error-handling policy
...
In a ‘‘production
design,’’ the facet functions would either implement error handling for both input and output or just
report errors for >> and << to handle
...
An alternative design would have Season_io itself retrieve those strings from a locale-specific repository (see
§39
...
7)
...


39
...
3 Uses of locales and facets
The primary use of locales within the standard library is in I/O streams
...
The
messages facet (§39
...
7) is an example of a facet that has nothing to do with I/O streams
...
Also, a user may use locales as a convenient way of organizing arbitrary culturesensitive information
...
Plausible candidates for representation as facets are dates, time zones, phone numbers, social security numbers (personal identification numbers), product codes, temperatures, general (unit,value) pairs, postal codes (zip codes), clothing sizes, and ISBN numbers
...
That something can
be represented as a facet doesn’t mean that it is best represented that way
...


1124

Locales

Chapter 39

39
...
22
...
1
...
1)
collate

numeric

String comparison
Numeric formatting

monetary

Money formatting

moneypunct
moneypunct
money_get
money_put

§39
...
3

time

Date and time formatting

time_put
time_put_byname
time_get

§39
...
4

ctype

Character classification

ctype
codecvt
codecvt_byname

§39
...
5

messages

Message retrieval

messages

§39
...
7

collate

numpunct
num_get
num_put

§39
...
1
§39
...
2

The details are explained in the referenced subsections
...
1)
...
In addition, ctype is guaranteed to support
char16_t and char32_t
...

For example, codecvt (§39
...
6) might be needed to control conversions between
X and char
...
4
...
1), such as USD and BRL
...
4
...
In , mbstate_t is defined to represent any of the conversion states that
can occur in an implementation-defined set of supported multibyte character encoding rules
...
2
...

In and Out are input iterators and output iterators, respectively (§33
...
2, §33
...
4)
...
4
...
2)
...
6
...
4
...
2)
...
6
...

Each standard facet has a _byname version
...

F_byname provides the identical interface to F, except that it adds a constructor taking a string argument naming a locale (e
...
, see §39
...
1)
...
For example:

Section 39
...
begin(),v
...
2
...
This implies that _byname constructors are very slow compared to constructors that do not need to consult the environment
...
Thus,
reading a facet from the environment once and then using the copy in main memory repeatedly is
usually a good idea
...
begin(),v
...

}

This dk2 locale will use Danish-style strings but will retain the default conventions for numbers
...
For
example, given the dk locale, we can construct a locale that reads and compares strings according to
the rules of Danish (which has three more vowels than English) but that retains the syntax of numbers used in C++:
locale dk_us(locale::classic(),dk,collate|ctype);

// Danish letters, American numbers

The presentations of individual standard facets contain more examples of facet use
...
4
...

Standard facets often depend on each other
...
Only
if you have a detailed knowledge of individual facets can you successfully mix and match facets or
add new versions of the standard facets
...
For an extensive discussion of locales, see [Langer,2000]
...
The reason is partially that facets have to
reflect messy cultural conventions outside the control of the library designer, and partially that the
C++ standard library-facilities have to remain largely compatible with what is offered by the C
standard library and various platform-specific standards
...
A facet
can be designed to hold any data, and the facet’s operations can provide any desired operation based
on that data
...
3
...


1126

Locales

Chapter 39

39
...
1 string Comparison
The standard collate facet provides ways of comparing arrays of characters:
template
class collate : public locale::facet {
public:
using char_type = C;
using string_type = basic_string;
explicit collate(size_t = 0);
int compare(const C∗ b, const C∗ e, const C∗ b2, const C∗ e2) const
{ return do_compare(b,e,b2,e2); }
long hash(const C∗ b, const C∗ e) const
{ return do_hash(b,e); }
string_type transform(const C∗ b, const C∗ e) const
{ return do_transform(b,e); }
static locale::id id; // facet identifier object (§39
...
3, §39
...
1)
protected:
˜collate(); // note: protected destructor
virtual int do_compare(const C∗ b, const C∗ e, const C∗ b2, const C∗ e2) const;
virtual string_type do_transform(const C∗ b, const C∗ e) const;
virtual long do_hash(const C∗ b, const C∗ e) const;
};

This defines two interfaces:
• The public interface for users of the facet
...

The constructor argument specifies whether a locale or a user is responsible for deleting the facet
...
3)
...
22
...
4
...
To derive from a standard pattern, simply define the
do_∗ versions of the key functions providing the facet’s functionality
...
For an example, see §39
...
1
...

The hash() function calculates a hash value for its imput string
...


Section 39
...
1

string

Comparison

The transform() function produces a string that, when compared to another
gives the same result as comparing the strings
...
compare(cf
...
transform(s2)) == cf
...
This is useful when implementing a search among a set of strings
...
It returns:
1 if the first string is lexicographically greater than the second
0 if the strings are identical
−1 if the second string is greater than the first
For example:
void f(const string& s1, const string& s2, const collate& cmp)
{
const char∗ cs1 {s1
...
data()};
switch (cmp
...
size(),cs2,cs2+s2
...

break;
case −1:
// s1 < s2
//
...

break;
}
}

The collate member functions compare [b:e) ranges of C rather than basic_strings or zero-terminated C-style strings
...

The standard-library string is not locale sensitive
...
2
...
Furthermore, the standard string does not provide a direct way of specifying comparison criteria (Chapter 36)
...
For example:
void f(const string& s1, const string& s2, const string& name)
{
bool b {s1==s2};
// compare using implementation’s character set values
const char∗ s1b {s1
...
data()+s1
...
data()};
const char∗ s2e {s2
...
size()}

// get start of data
// get end of data

1128

Locales

Chapter 39

using Col = collate;
const Col& global {use_facet(locale{})};
int i0 {global
...
compare(s1b,s1e,s2b,s2e)};

// from my preferred locale

const Col& n_coll {use_facet(locale{name})};
int i2 {n_coll
...
2
...
For example:
void f(const string& s1, const string& s2, const string& name)
{
int i0 = locale{}(s1,s2);
// compare using the current global locale
int i1 = locale{""}(s1,s2);
// compare using my preferred locale
int i2 = locale{name}(s1,s2); // compare using the named locale
//
...
Consider this sequence of words

Dialekt, Diat, dich, dichten, Dichtung
¨

According to convention, nouns (only) are capitalized, but the ordering is not case sensitive
...
However, in most common char¨
acter sets, the numeric value of a is larger than the numeric value of c
...


39
...
1
...
4
...
1

Named collate

1129

protected:
˜collate_byname(); // note: protected destructor
int do_compare(const C∗ b, const C∗ e, const C∗ b2, const C∗ e2) const override;
string_type do_transform(const C∗ b, const C∗ e) const override;
long do_hash(const C∗ b, const C∗ e) const override;
};

Thus, a collate_byname can be used to pick out a collate from a locale named in the program’s
execution environment (§39
...
One obvious way of storing facets in an execution environment
would be as data in a file
...


39
...
2 Numeric Formatting
Numeric output is done by a num_put facet writing into a stream buffer (§38
...
Conversely,
numeric input is done by a num_get facet reading from a stream buffer
...


39
...
2
...
22
...
6
...
1)

E
...

E
...
, ’,’
E
...
, "" meaning ‘‘no grouping’’
E
...
, "true"
E
...
, "false"

The characters of the string returned by grouping() are read as a sequence of small integer values
...
Character 0 specifies the rightmost group
(the least significant digits), character 1 the group to the left of that, etc
...
If necessary, the last number in a grouping pattern is used repeatedly, so "\003" is equivalent to
"\003\003\003"
...
The
grouping() and thousands_sep() functions define a format for both input and output of integers and
the integer part of floating-point values
...
For example, I could define
facet My_punct to write integer values using spaces to group the digits in sets of three and floatingpoint values, using a European-style comma as the ‘‘decimal point’’:
class My_punct : public numpunct {
public:
explicit My_punct(size_t r = 0) :numpunct(r) { }
protected:
char do_decimal_point() const override { return ','; }

// comma

1130

Locales

Chapter 39

char do_thousands_sep() const override { return '_'; }
string do_grouping() const override { return "\003"; }

// underscore
// 3-digit groups

};
void f()
{
cout << "style A: " << 12345678
<< " ∗∗∗ " << 1234567
...
8 << '\n';
cout << defaultfloat;
// reset floating format
locale loc(locale(),new My_punct);
cout
...
8
<< " ∗∗∗ " << fixed << 1234567
...
23457e+06 ∗∗∗ 1234567
...
Consequently, a stream can rely on an
imbued locale even after the original copy of that locale has been destroyed
...
4
...
1), the strings returned by truename() and falsename() are used to represent true and false, respectively; otherwise, 1 and 0 are used
...
4, §39
...
1) of numpunct is provided:
template
class numpunct_byname : public numpunct {
//
...
4
...
2 Numeric Output
When writing to a stream buffer (§38
...
22
...
2
...


Section 39
...
2
...
4)
...
For example, here is a very simple num_put
for writing into a string:
template
class String_numput : public num_put::iterator> {
public:
String_numput() :num_put::iterator>{1} { }
};

I don’t mean for String_numput to go into a locale, so I used the constructor argument to retain ordinary lifetime rules
...
put(s
...


For

void test(iostream& io)
{
locale loc = io
...
widen(c);
string s = use_facet>(loc)
...
falsename();

// char to C conversion
// default: ’
...
Consequently, most programmers need not know about it
...
As ever, the standard library provides examples of interesting programming techniques
...
4
...
put(∗this,∗this,this−>fill(),d)
...
) {
handle_ioexception(∗this);
}
return ∗this;
}

A lot is going on here
...
4
...
We get the ostream’s locale by calling its member function getloc() (§38
...
5
...
We
extract num_put from that locale using use_facet (§39
...
1)
...
An ostreambuf_iterator can be constructed from an ostream (§38
...
3),
and an ostream can be implicitly converted to its base class ios_base (§38
...
4), so the first two arguments to put() are easily supplied
...
This output iterator is obtained from a
basic_ostream, so it is an ostreambuf_iterator
...
6
...

I did not use has_facet, because the standard facets (§39
...
If that guarantee is violated, bad_cast is thrown (§39
...
1)
...
Consequently, user-defined code may be executed,
and operator<<() must be prepared to handle an exception thrown by the overriding do_put()
...
3
...

The behavior of a << for a built-in type, such as double, is defined by the C++ standard
...
If badbit is set in this ostream’s exception state (§38
...
Otherwise, an exception is handled by setting the stream state and continuing
...
4
...
1):
template
void handle_ioexception(basic_ostream& s)// called from catch-clause
{
if (s
...
setstate(ios_base::badbit); // might throw basic_ios::failure
}
catch(
...
do nothing
...
setstate(ios_base::badbit);
}

The try-block is needed because setstate() might throw basic_ios::failure (§38
...
4
...
1)
...

The << for a built-in type, such as double, must be implemented by writing directly to a stream
buffer
...
3
...


Section 39
...
2
...
4
...
3 Numeric Input
When reading from a stream buffer (§38
...
22
...
2
...
4
...
2)
...

The iostate variable r is set to reflect the state of the stream
...
An input operator
will use r to determine how to set the state of its stream
...

A sentry is used to ensure that the stream’s prefix and suffix operations are performed (§38
...
1)
...
For example, an implementer of istream might write:
template
basic_istream& basic_istream::operator>>(double& d)
{
sentry guard(∗this);
// see §38
...
1
if (!guard) return ∗this;
iostate state = 0;
// good
istreambuf_iterator eos;
try {
double dd;
use_facet>(getloc())
...
) {
handle_ioexception(∗this);
// see §39
...
2
...
Unfortunately,
that cannot be guaranteed for all input operations
...
3)
...
4
...
1, we can read using nonstandard punctuation
...
imbue(loc);
cout << "style B: "
int i2;
double d2;
cin >> i1 >> d2;
// read using the ‘‘12_345_678’’ format
}

If we want to read really unusual numeric formats, we have to override do_get()
...


39
...
3 Money Formatting
The formatting of monetary amounts is technically similar to the formatting of ‘‘plain’’ numbers
(§39
...
2)
...
For example, a negative amount (a loss, a debit), such as −1
...
25)
...

There is no standard ‘‘money type
...
For example:
struct Money {
using Value = long long;
Value amount;
};

// simple type to hold a monetary amount
// for currencies that have suffered inflation

//
...
4
...
2)
...
Possible outputs are:

Section 39
...
3

Money Formatting

1135

value= 1234567 amount= $12345
...
67
value= −1234567 amount= −€12345
...
Consequently, I
adopted the common convention of having the integer value represent the number of cents (pence,
øre, fils, cents, etc
...
This convention is supported by moneypunct’s frac_digits() function (§39
...
3
...
Similarly, the appearance
of the ‘‘decimal point’’ is defined by decimal_point()
...

A simple Money type can be used to control I/O formats or to hold monetary values
...
It is less error-prone to
consistently hold monetary amounts in a Money type; that way, we cannot forget to cast a value to
Money before writing it, and we don’t get input errors by trying to read monetary values in localeinsensitive ways
...
In such cases, applying Money conversions (casts) to read and write operations is
necessary
...
4
...
1 Money Punctuation
The

controlling the presentation of monetary amounts,
for controlling plain numbers, numpunct (§39
...
2
...

};

naturally resembles the

1136

Locales

Chapter 39

The moneypunct member functions define the layout of money input and output:
moneypunct> facet
C decimal_point() const;
C thousands_sep() const;
string grouping() const;
string_type curr_symbol() const;
string_type positive_sign() const;
string_type negative_sign() const;
int frac_digits() const;
pattern pos_format() const;
pattern neg_format() const;
static const bool intl = International;

(§iso
...
4
...
3)

E
...

E
...
, ’,’
E
...
, "" meaning ‘‘no grouping’’
E
...
, "$"
E
...
, ""
E
...
, "−"
Number of digits after "
...
g
...
4
...
2, §39
...
3
...

A _byname version (§39
...
4
...

};

The decimal_point(), thousands_sep(), and grouping() members behave as in numpunct
...
If the International template argument is true, the intl member will also be true, and
‘‘international’’ representations of the currency symbols will be used
...
For example:
"USD"
"DKK"
"EUR"

The last (invisible) character is a terminating zero
...
When International is false, a ‘‘local’’ currency symbol, such as $, £, and ¥,
can be used
...
Most common
formats are trivially represented using this simple notion of a pattern
...
45
$+123
...
45
$123
...
45 DKK
($123
...
45DKK)

// { sign, symbol, space, value } where positive_sign() returns "+"
// { symbol, sign, value, none } where positive_sign() returns "+"
// { symbol, sign, value, none } where positive_sign() returns ""
// { symbol, value, sign, none }
// { sign, value, space, symbol }
// { sign, symbol, value, none } where negative_sign() returns "()"
// { sign, value, symbol, none } where negative_sign() returns "()"

Section 39
...
3
...
The first character of a sign string is placed where sign is
found in the pattern, and the rest of the sign string is placed after all other parts of the pattern
...
For example:
−$123
...
45 silly

// { sign, symbol, value, none } where negative_sign() returns "−"
// { sign, symbol, value, none } where negative_sign() returns "* silly"

Each of the values sign, value, and symbol must appear exactly once in a pattern
...
Where space appears, at least one and possibly more whitespace
characters may appear in the representation
...

Note that these strict rules ban some apparently reasonable patterns:
pattern pat = { sign, value, none, none };

// error : no symbol

The frac_digits() function indicates where the decimal_point() is placed
...
4
...
This unit is typically one-hundredth of the
major unit (for example, a ¢ is one-hundredth of a $), so frac_digits() is often 2
...
'; }
char_type do_thousands_sep() const { return ','; }
string do_grouping() const { return "\003\003\003"; }
string_type do_curr_symbol() const { return "USD "; }
string_type do_positive_sign() const { return ""; }
string_type do_negative_sign() const { return "()"; }
int do_frac_digits() const { return 2; }

// two digits after decimal point

pattern do_pos_format() const { return pat; }
pattern do_neg_format() const { return pat; }
private:
static const pattern pat;
};
const pattern My_money_io::pat { sign, symbol, value, none };

39
...
3
...

Specifically, money_put provides put() functions that place a suitably formatted character representation into the stream buffer of a stream:

1138

Locales

Chapter 39

money_put> facet
Put value v into buffer position b

(§iso
...
4
...
2)

Out put(Out b, bool intl, ios_base& s, C fill, long double v) const;
Out put(Out b, bool intl, ios_base& s, C fill, const string_type& v) const;

The intl argument indicates whether a standard four-character ‘‘international’’ currency symbol or a
‘‘local’’ symbol is used (§39
...
3
...

Given money_put, we can define an output operator for Money (§39
...
3):
ostream& operator<<(ostream& s, Money m)
{
ostream::sentry guard(s);
// see §38
...
1
if (!guard) return s;
try {
const money_put& f = use_facet>(s
...
put(s,true,s,s
...
failed())
s
...
put(s,true,s,s
...
str())
...
setstate(ios_base::badbit);
}
}
catch (
...
4
...
2

}

If a long long doesn’t have sufficient precision to represent the monetary value exactly, I convert the
value to its string representation and output that using the put() that takes a string
...
4
...
3 Money Input
The money_get facet reads monetary amounts according to the format specified by moneypunct
...
22
...
6
...
For example:

Section 39
...
3
...
Furthermore, the output produced by a second run given the output from a first run should be identical to its input
...
sentr y_
if (guard) try {
ios_base::iostate state = 0;
// good
istreambuf_iterator eos;
string str;
use_facet>(s
...
get(s,eos,true,state,str);
if (state==0 || state==ios_base::eofbit) { // set value only if get() succeeded
long long i = stoll(str);
// §36
...
5
if (errno==ERANGE) {
state |= ios_base::failbit;
}
else {
m = i;
// set value only if conversion to long long succeeded
}
s
...
) {
handle_ioexception(s);
}
return s;

// see §39
...
2
...

The largest value that can be exactly represented by a long double may be smaller than the
largest value that can be represented by a long long
...
4
...
The representation of
dates and times used is tm (§43
...


1140

Locales

Chapter 39

39
...
4
...
6) or an equivalent
...
22
...
5
...
For each strftime() format character
x, with optional modifier mod, it calls do_put(s,ib,pt,x,mod)
...
An overriding p=do_put(s,ib,pt,x,mod) is supposed to format the
appropriate parts of ∗pt into s and return a value pointing to the position in s after the last character
written
...
4, §39
...
1) of messages is provided:
template>
class time_put_byname : public time_put
{
//
...
4
...
2 time_get
The basic idea is that a
format (§43
...

}

In addition to reading according to a format, there are operations for examining the dateorder and
for reading specific parts of date and time representations, such as weekday and monthname:

Section 39
...
4
...
22
...
5
...

It returns an iterator pointing to the first unread character in [b:e)
...
If mod is not specified, mod==0 is used
...

This overload, together with the one with the defaulted modifier, does not have do_get() interfaces
...

The obvious use of the time and date facets is to provide locale-sensitive I/O for a Date class
...
3:
class Date {
public:
explicit Date(int d ={}, Month m ={}, int year ={});
//
...
2
...
imbue(loc);
return os << ∗this;
}

Given to_string(), the output operator is trivial:
ostream& operator<<(ostream& os, Date d)
{
return os< ...
getloc())
...
tm_mon+1);
d = Date(t
...
tm_year+1900);
}
is
...
6)
...
4, §39
...
1) of messages is provided:
template>
class time_get_byname : public time_get {
//
...
4
...
For example, to read a number, an input routine needs to know which letters are digits
...
2
...

Naturally, classification of characters depends on the alphabet used
...

The character classes are described by an enumeration called mask:
class ctype_base {
public:
enum mask {
// the actual values are implementation-defined
space = 1,
// whitespace (in "C" locale: ’ ’, ’\n’, ’\t’,
...
4
...

};

This mask doesn’t depend on a particular character type
...

Clearly, mask reflects the traditional C and C++ classification (§36
...
1)
...
For example, for the ASCII
character set, the integer value 125 represents the character }, which is a punctuation character
(punct)
...

The classification is called a ‘‘mask’’ because the traditional efficient implementation of character classification for small character sets is a table in which each entry holds bits representing the
classification
...

The ctype facet is defined like this:
ctype facet

(§iso
...
4
...
1)

bool is(mask m, C c) const;
const C∗ is(const C∗ b, const C∗ e, mask∗ v) const;
const C∗ scan_is(mask m, const C∗ b, const C∗ e) const;
const C∗ scan_not(mask m, const C∗ b, const C∗ e) const;
C toupper(C c) const;
const C∗ toupper(C∗ b, const C∗ e) const;
C tolower(C c) const;
const C∗ tolower(C∗ b, const C∗ e) const;
C widen(C c) const;
const char∗ widen(const char∗ b, const char∗ e, C∗ b2) const;
char narrow(C c, char def) const;
const C∗ narrow(const C∗ b, const C∗ e, char def, char∗ b2) const;

A call is(m,c) tests whether the character c belongs to the classification m
...
begin(); p!=s
...
is(ctype_base::space,∗p))
++i;
return i;

// whitespace as defined by ct

}

Note that it is also possible to use
classifications
...
is(ctype_base::space|ctype_base::punct,c);

// is c whitespace or punctuation in ct?

A call is(b,e,v) determines the classification of each character in [b:e) and places it in the corresponding position in the array v
...
If no character
is classified as an m, e is returned
...
A simple implementation might be:
template
const C∗ ctype::do_scan_is(mask m, const C∗ b, const C∗ e) const
{
while (b!=e && !is(m,∗b))
++b;
return b;
}

A call scan_not(m,b,e) returns a pointer to the first character in [b:e) that is not an m
...

A call toupper(c) returns the uppercase version of c if such a version exists in the character set
used and c itself otherwise
...
A simple implementation might be:
template
const C∗ ctype::to_upper(C∗ b, const C∗ e)
{
for (; b!=e; ++b)
∗b = toupper(∗b);
return e;
}

The tolower() functions are similar to toupper() except that they convert to lowercase
...
If C’s character set
provides several characters corresponding to c, the standard specifies that ‘‘the simplest reasonable
transformation’’ be used
...
getloc())
...

Translation between unrelated character representations, such as ASCII and EBCDIC, can also
be done by using widen()
...
4
...
widen('e');

A call widen(b,e,v) takes each character in the range [b:e) and places a widened version in the corresponding position in the array v
...

Again, ‘‘the simplest reasonable transformation’’ is to be used
...

A call narrow(b,e,def,v) takes each character in the range [b:e) and places a narrowed version in
the corresponding position in the array v
...
For a character c from the smaller character set, we expect:
c == narrow(widen(c),0) // not guaranteed

This is true provided that the character represented by c has only one representation in ‘‘the smaller
character set
...
If the characters represented by a char are not a
subset of those represented by the larger character set (C), we should expect anomalies and potential problems with code treating characters generically
...
For
example, a digit, such as 7, often has several separate representations in a large character set
...

For every character in the basic source character set (§6
...
2), it is guaranteed that
widen(narrow(ch_lit,0)) == ch_lit

For example:
widen(narrow('x',0)) == 'x'

The narrow() and widen() functions respect character classifications wherever possible
...

A major reason for using a ctype facet in general and for using narrow() and widen() functions in
particular is to be able to write code that does I/O and string manipulation for any character set, that
is, to make such code generic with respect to character sets
...
By relying on and , a user can avoid
most direct uses of the ctype facet
...
4, §39
...
1) of ctype is provided:
template
class ctype_byname : public ctype {
//
...
4
...
For example, Japanese characters are often stored in
files in which indicators (‘‘shifts’’) indicate to which of the four common character sets (kanji,
katakana, hiragana, and romaji) a given sequence of characters belongs
...
In main memory, these characters are easier
to manipulate when represented in a multibyte character set where every character has the same
size
...
2
...
Consequently, the codecvt facet provides a mechanism for converting characters
from one representation to another as they are read or written
...
It allows us to write a program to use a suitable internal character representation
(stored in char, wchar_t, or whatever) and to then accept a variety of input character stream representations by adjusting the locale used by iostreams
...

The codecvt facet provides conversion between different character sets when a character is
moved between a stream buffer and external storage:
class codecvt_base {
public:
enum result {
// result indicators
ok, partial, error, noconv
};
};
template
class codecvt : public locale::facet, public codecvt_base {
public:
using intern_type = In;
using extern_type = Ex;
using state_type = SS;
//
...
4
...
22
...
2
...
A basic_filebuf obtains
this facet from the stream’s locale (§38
...

The State template argument is the type used to hold the shift state of the stream being converted
...
The
latter is useful because characters of a variety of character encodings (character sets) can be stored
in objects of the same type
...
*/ };
p = new codecvt;
q = new codecvt;

// standard char to wide char
// JIS to wide char

Without the different State arguments, there would be no way for the facet to know which encoding
to assume for the stream of chars
...
h> identifies the
system’s standard conversion between char and wchar_t
...
For example:
class JIScvt : public codecvt {
//
...
If a
character is converted, in() writes its converted form to the corresponding position in the [b2:e2)
range; if not, in() stops at that point
...
The result value returned by in() indicates how much
work was done:
codecvt_base result
ok
partial
error
noconv

(§iso
...
4
...
4)

All characters in [b:e) range were converted
Not all characters in [b:e) were converted
A character couldn’t be converted
No conversion was needed

Note that a partial conversion is not necessarily an error
...


1148

Locales

Chapter 39

The state_type argument st indicates the state of the input character sequence at the start of the
call of in()
...
Note that
st is a (non-const) reference argument: at the end of the call, st holds the shift state of the input
sequence
...

A call out(st,b,e,next,b2,e2,next2) converts [b:e) from the internal to the external representation
in the same way the in() converts from the external to the internal representation
...
Typically, that state is
state_type{}
...
The result of unshift() and the use of next are done just
like out()
...

Return values from encoding() mean:
−1 The encoding of the external character set uses state (for example, uses shift and unshift
character sequences)
...

n Every character of the external character representation is n bytes
...
Clearly, always_noconv()==true opens the possibility for the
implementation to provide the maximally efficient implementation that simply doesn’t invoke the
conversion functions
...
max_length() returns the maximum value that cvt
...

The simplest code conversion that I can think of is one that converts input to uppercase
...
4
...

}
int main() // trivial test
{
locale ulocale(locale(), new Cvt_to_upper);
cin
...
4, §39
...
1) of codecvt is provided:
template
class codecvt_byname : public codecvt {
//
...
4
...
However,
we cannot provide a standard mechanism for expressing locale-specific general interactions
...
In essence, messages implements a trivial
read-only database:

1150

Locales

Chapter 39

class messages_base {
public:
using catalog = /* implementation-defined integer type */; // catalog identifier type
};
template
class messages : public locale::facet, public messages_base {
public:
using char_type = C;
using string_type = basic_string;
//
...
22
...
7
...
A catalog is a set of
strings organized in an implementation-specific way and accessed through the messages::get() function
...
A catalog must be opened
before the first use of get()
...

A call get(cat,set,id,"foo") looks for a message identified by (set,id) in the catalog cat
...

Here is an example of a messages facet for an implementation in which a message catalog is a
vector of sets of ‘‘messages’’ and a ‘‘message’’ is a string:
struct Set {
vector msgs;
};
struct Cat {
vector sets;
};
class My_messages : public messages {
vector& catalogs;
public:
explicit My_messages(size_t = 0) :catalogs{∗new vector} { }
catalog do_open(const string& s, const locale& loc) const; // open catalog s
string do_get(catalog cat, int s, int m, const string&) const; // get message (s,m) in cat

Section 39
...
7

Messages

1151

void do_close(catalog cat) const
{
if (catalogs
...
erase(catalogs
...

A message is selected by specifying a catalog, a set within that catalog, and a message string
within that set
...
size()<=cat)
return def;
Cat& c = catalogs[cat];
if (c
...
size()<=set)
return def;
Set& s = c
...
msgs
...
msgs[id];
}

Opening a catalog involves reading a textual representation from disk into a Cat structure
...
A set is delimited by <<< and >>>, and each message is
a line of text:
messages::catalog My_messages::do_open(const string& n, const locale& loc) const
{
string nn = n + locale()
...
c_str());
if (!f) return −1;
catalogs
...
back();

// make in-core catalog

for(string s; f>>s && s=="<<<"; ) {
c
...
push_back(Set{});
Set& ss = c
...
back();
while (getline(f,s) && s != ">>>")
ss
...
push_back(s);
}
return catalogs
...
name() << '\n';
exit(1);
}
const messages& m = use_facet(locale());
extern string message_directory;
// where I keep my messages
auto cat = m
...
get(cat,0,0,"Missed again!") << endl;
cout << m
...
get(cat,1,3,"Missed again!") << endl;
cout << m
...
4
...
1 Using Messages from Other facets
In addition to being a repository for locale-dependent strings used to communicate with users, messages can be used to hold strings for other facets
...
3
...
4
...
1

Using Messages from Other facets

1153

class Season_io : public locale::facet {
const messages& m;
// message directory
messages_base::catalog cat;
// message catalog
public:
class Missing_messages { };
Season_io(size_t i = 0)
: locale::facet(i),
m(use_facet(locale())),
cat(m
...
3)

const string& to_str(Season x) const;

// string representation of x

bool from_str(const string& s, Season& x) const; // place Season corresponding to s in x
static locale::id id; // facet identifier object (§39
...
3, §39
...
1)
};
locale::id Season_io::id; // define the identifier object
string Season_io::to_str(Season x) const
{
return m−>get(cat,0,x,"no−such−season");
}
bool Season_io::from_str(const string& s, Season& x) const
{
for (int i = Season::spring; i<=Season::winter; i++)
if (m−>get(cat,0,i,"no−such−season") == s) {
x = Season(i);
return true;
}
return false;
}

This messages-based solution differs from the original solution (§39
...
2) in that the implementer of
a set of Season strings for a new locale needs to be able to add them to a messages directory
...
However, since messages
provides only a read-only interface, adding a new set of season names may be beyond the scope of
an application programmer
...
4, §39
...
1) of messages is provided:

1154

Locales

Chapter 39

template
class messages_byname : public messages {
//
...
5 Convenience Interfaces
Beyond simply imbuing an iostream, the locale facilities can be complicated to use
...


39
...
1 Character Classification
The most common use of the ctype facet is to inquire whether a character belongs to a given classification
...
22
...
3
...
For example:
template
inline bool isspace(C c, const locale& loc)
{
return use_facet>(loc)
...
2
...
Except for
the rare cases in which the C global locale and the C++ global locale differ (§39
...
1), we can think
of a one-argument version as the two-argument version applied to locale()
...
5
...
5
...
22
...
3
...
1)
c2= toupper(c,loc)
c2= tolower(c,loc)

use_facet>(loc)
...
tolower(c)

39
...
3 String Conversions
Character code conversions can be locale sensitive
...
It lets you specify a code conversion facet (such
as codecvt) to perform the conversions, without affecting any streams or locales
...
to_bytes(L"Hello\n");
cout << s;

The definition of wstring_convert is fairly conventional:
templateclass Wc = wchar_t,
class Wa = std::allocator,
// wide-character allocator
class Ba = std::allocator
// byte allocator
>
class wstring_convert {
public:
using byte_string = basic_string, Ba>;
using wide_string = basic_string, Wa>;
using state_type = typename Codecvt::state_type;
using int_type = typename wide_string::traits_type::int_type;
//
...
˜wstring_convert();

(§iso
...
3
...
2
...
from_bytes(c)
ws=cvt
...
from_bytes(b,e)
s=cvt
...
to_bytes(ws)
s=cvt
...
converted()
st=cvt
...
22
...
3
...
2)

ws contains the char c converted to Wcs
ws contains the chars of s converted to Wcs;
s is a C-style string or a string
ws contains the chars of [b:e) converted to Wcs
s contains wc converted to chars
s contains the Wcs of wsconverted to a chars;
ws is a C-style string or a basic_string
s contains the Wcs of [b:e) converted to chars
n is the number of input elements converted by cvt
st is the cvt’s state

If a conversion to a wide_string fails, functions on a cvt constructed with a non-default w_err string
return that string (as an error message); otherwise, they throw range_error
...

An example:
void test()
{
wstring_convert> converter;
string s8 = u8"This is a UTF−8 string";
wstring s16 = converter
...
to_bytes(s16);
if (s8!=s88)
cerr <"Insane!\n";
}

39
...
4 Buffer Conversions
We can use a code conversion facet (§39
...
6) to write directly into or to read directly from a stream
buffer (§38
...

};

Section 39
...
4

Buffer Conversions

wbuffer_convert

1157

(§iso
...
3
...
2
...
rdbuf()
psb2=wb
...
state()

39
...
1
...
1, §39
...
1
...
1
...
1
...
2
...
2
...

Keep changes of locale to a few places in a program; §39
...
1
...
2
...

Prefer locale-sensitive string comparisons and sorts; §39
...
2, §39
...
1
...
3
...
3
...
3
...

When writing locale-sensitive I/O functions, remember to handle exceptions from user-supplied (overriding) functions; §39
...
2
...

Use numput if you need separators in numbers; §39
...
2
...

Use a simple Money type to hold monetary values; §39
...
3
...
4
...

The time_put facet can be used for both - and -style time §39
...
4
...
4
...
5
...

– R
...
Hamming

...

– A
...
1 Introduction
C++ was not designed primarily with numeric computation in mind
...
Furthermore, numeric methods have come a long
way from being simple loops over vectors of floating-point numbers
...
The net effect is
that C++ is widely used for scientific, engineering, financial, and other computation involving
sophisticated numerics
...
This chapter describes the parts of the standard library that support numerics
...
Numeric computation is a fascinating topic in its own right
...

In addition to the standard-library facilities described here, Chapter 29 is an extended example
of numerical programming: an N-dimensional matrix
...
2 Numerical Limits
To do anything interesting with numbers, we typically need to know something about the general
properties of built-in numeric types
...
2
...
For example, what is the largest int? What is the smallest positive float? Is a double
rounded or truncated when assigned to a float? How many bits are there in a char?
Answers to such questions are provided by the specializations of the numeric_limits template
presented in
...
Thus, the general
numeric_limits template is simply a notational handle for a set of constants and constexpr functions:
template
class numeric_limits {
public:
static const bool is_specialized = false; // is information available for numeric_limits?
//
...

};

Section 40
...
Each implementation of the standard library provides
a specialization of numeric_limits for each fundamental numeric type (the character types, the integer types, the floating-point types, and bool) but not for any other plausible candidates such as void,
enumerations, or library types (such as complex)
...
Here is
numeric_limits for an implementation in which a char has 8 bits and is signed:
template<>
class numeric_limits {
public:
static const bool is_specialized = true; // yes, we have information
static const int digits = 7;

// number of bits (‘‘binar y digits’’) excluding sign

static const bool is_signed = true;
static const bool is_integer = true;

// this implementation has char signed
// char is an integral type

static constexpr char min() noexcept { return −128; }
static constexpr char max() noexcept { return 127; }

// smallest value
// largest value

// lots of declarations not relevant to a char
};

The functions are constexpr, so that they can be used where a constant expression is required and
without run-time overhead
...
For example,
this describes one possible implementation of float:
template<>
class numeric_limits<float> {
public:
static const bool is_specialized = true;
static const int radix = 2;
static const int digits = 24;
static const int digits10 = 9;

// base of exponent (in this case, binar y)
// number of radix digits in mantissa
// number of base 10 digits in mantissa

static const bool is_signed = true;
static const bool is_integer = false;
static const bool is_exact = false;
static constexpr float min() noexcept { return 1
...
40282347E+38F; } // largest positive
static constexpr float lowest() noexcept { return −3
...
19209290E−07F; }
static constexpr float round_error() noexcept { return 0
...

When defining a scalar type along the lines of the built-in ones, it is a good idea also to provide
a suitable specialization of numeric_limits
...
Conversely, if I use a nonnumeric type, Dumb_ptr, I would expect for numeric_limits> to be the primary template that has is_specialized set to false, indicating that no information is available
...
In such cases, it is usually better to use the general technique for describing properties of a type than to specialize numeric_limits with properties
not considered in the standard
...
2
...
They are found in :
Integer Limit Macros (_iso
...
library_, abbreviated)
CHAR_BIT
CHAR_MIN
CHAR_MAX
INT_MIN
LONG_MAX

Number of bits in a char (usually 8)
Smallest char value (possibly negative)
Largest char value (usually 127 if char is signed and 255 if char is unsigned)
Smallest int value
Largest long value

Analogously named macros for signed chars, long long, etc
...


Section 40
...
1

Limit Macros

1163

Similarly, and <float
...
diff
...
g
...
175494351e−38F)
Largest float value (e
...
, 3
...
g
...
g
...
g
...
7976931348623158e+308)
Smallest double such that 1
...
0

Analogously named macros for long double are also provided
...
3 Standard Mathematical Functions
In we find what are commonly called the standard mathematical functions:
Standard Mathematical Functions
abs(x)
ceil(x)
floor(x)
sqrt(x)
cos(x)
sin(x)
tan(x)
acos(x)
asin(x)
atan(x)
sinh(x)
cosh(x)
tanh(x)
exp(x)
log(x)
log10(x)

Absolute value
Smallest integer >= x
Largest integer <= x
Square root; x must be non-negative
Cosine
Sine
Tangent
Arccosine; the result is non-negative
Arcsine; the result nearest to 0 is returned
Arctangent
Hyperbolic sine
Hyperbolic cosine
Hyperbolic tangent
Base e exponential
Natural logarithm, base e; x must be positive
Base 10 logarithm

There are versions taking float, double, long double, and complex (§40
...
For each function, the return type is the same as the argument type
...
For example:
void f()
{
errno = 0; // clear old error state
sqrt(−1);
if (errno==EDOM) cerr << "sqrt() not defined for negative argument";

1164

Numerics

Chapter 40

pow(numeric_limits::max(),2);
if (errno == ERANGE) cerr << "result of pow() too large to represent as a double";
}

For historical reasons, a few mathematical functions are found in rather than in :
More Mathematical Functions (§iso
...
8)
n2=abs(n)
n2=labs(n)
n2=llabs(n)

Absolute value; n is int, long, or long long; n2 has the same type as n
‘‘Long absolute value’’; n and n2 are long
‘‘Long long absolute value’’; n and n2 are long long

p=div(n,d)
p=ldiv(n,d)
p=lldiv(n,d)

Divide n by d; p is {quotient,remainder}; n and d are long
Divide n by d; p is {quotient,remainder}; n and d are long long

p=div(n,d)

The l∗() versions are there because C does not support overloading
...
These structs have members quot (for quotient) and rem (for remainder) of implementation-defined types
...
An
implementation may add these functions to :
Mathematical Special Functions (Optional)
assoc_laguerre()
comp_ellint_2()
cyl_bessel_k()
ellint_3()
legendre()
sph_neumann()

assoc_legendre()
comp_ellint_3()
cyl_neumann()
expint()
riemann_zeta()

beta()
cyl_bessel_i()
ellint_1()
hermite()
sph_bessel()

comp_ellint_1()
cyl_bessel_j()
ellint_2()
laguerre()
sph_legendre()

If you don’t know these functions, you are unlikely to need them
...
4 complex Numbers
The standard library provides complex number types complex<float>, complex, and comA complex where Scalar is some other type supporting the usual arithmetic operations usually works but is not guaranteed to be portable
...


template
class complex {
// a complex is a pair of scalar values, basically a coordinate pair
Scalar re, im;
public:
complex(const Scalar & r = Scalar{}, const Scalar & i = Scalar{}) :re(r), im(i) { }
Scalar real() const { return re; }
void real(Scalar r) { re=r; }

// real part

Section 40
...
33333333333333333; // narrows
complex z2 = 1
...
33333333333333333};

// error : narrowing conversion

In addition to the members of complex, offers a host of useful operations:
complex
z1+z2
z1−z2
z1∗z2
z1/z2
z1==z2
z1!=z2
norm(z)
conj(z)
polar(x,y)
real(z)
imag(z)
abs(z)
arg(z)
out<in>>z

Operators

Addition
Subtraction
Multiplication
Division
Equality
Inequality
The square of abs(z)
Conjugate: {z
...
im}
Make a complex given polar coordinates (rho,theta)
Real part
Imaginary part
Distance from (0,0): sqrt(z
...
re+z
...
im); also known as rho
Angle from positive real axis: atan2(z
...
re); also known as theta
Complex output
Complex input

The standard mathematical functions (§40
...
Note that
complex does not provide < or %
...
3
...
5 A Numerical Array: valarray
Much numeric work relies on relatively simple single-dimensional vectors of floating-point values
...
The valarray from is a single-dimensional
numerical array
...
26
...
1)
valarray
slice
slice_array
gslice
gslice_array
mask_array
indirect_array

A numerical array of type T
A BLAS-like slice (start, length, and stride); §40
...
4
A subarray identified by a slice; §40
...
5
A slice generalized to describe a matrix
A submatrix identified by a generalized slice; §40
...
6
A subset of an array identified by a mask; §40
...
2
A subset of an array identified by a list of indices; §40
...
2

The fundamental idea of valarray was to provide Fortran-like facilities for dense multidimensional
arrays with Fortran-like opportunities for optimization
...
So far, that has not happened for all implementations
...
5
...
˜valarray()

Constructors (§iso
...
6
...
2)

with no elements
of n elements with value T{}; explicit
of n elements with value t
of n elements with values copied from [p:p+n)
Move and copy constructor
Construct va with elements from a;
a can be a slice_array, gslice_array, mask_array, or indirect_array;
the number of elements is the number of elements in a
Construct from the initializer_list {args};
the number of elements is the number of elements in {args}
Destructor

valarray
valarray
valarray
valarray

For example:
valarray v0;
valarray<float> v1(1000);

// placeholder, we can assign to v0 later
// 1000 elements with value float()==0
...
5
...
8064);

// 2000 elements with value −1
// bad mistake: floating-point valarray size

valarray v4 = v3;

// v4 has v3
...
This differs
from the convention for standard containers (§31
...
2)
...

Most programs need data from tables or input
...
For example:
void f(const int∗ p, int n)
{
const double vd[] = {0,1,2,3,4};
const int vi[] = {0,1,2,3,4};
valarray v1{vd,4};
valarray v2{vi,4};
valarray v3{vd,8};
valarray v4{p,n};

// 4 elements: 0,1,2,3
// type error: vi is not pointer to double
// undefined: too few elements in initializer
// p had better point to at least n ints

}

The valarray and its auxiliary facilities were designed for high-speed computing
...
Basically, an implementer of valarray is allowed to use just about every optimization technique you can think of
...
There is no range
checking
...
2
...

Assignment can be with another valarray, a scalar, or a subset of a valarray:
valarray
va2=va
va2=move(va)
va=t
va={args}
va=a
va@=va2
va@=t

Assignments (§iso
...
6
...
3)

Copy assignment: va2
...
size()
Move assignment: va becomes empty
Scalar assignment: each element of va is a copy of t
Assignment from the initializer_list {args};
the number of elements of va becomes {args}
...
size() must equal va
...
As one would expect, v1=v2 copies every
element of v2 into its corresponding position in v1
...


1168

Numerics

Chapter 40

In addition to this conventional assignment, it is possible to assign a scalar to a valarray
...
This may be surprising to some programmers and is best understood as an occasionally useful degenerate case of the operator assignment
operations
...
5
...
26
...
2
...
26
...
2
...
The return type (the type of the
object representing the subset) depends on the argument type
...
For non-const arguments, the
result holds references to elements
...
g
...
This can be done
efficiently
...
26
...
2
...
In each case, the
subscript describes the elements to be returned, and v1 must be a vallaray with an appropriate length
and element type:
• A slice of a const valarray:
valarray operator[](slice) const;// copy of elements
//
...

valarray v0 {"abcdefghijklmnop",16};
valarray v1 {"ABCDE",5};
v0[slice(2,5,3)] = v1;
// v0=={"abAdeBghCjkDmnEp",16}



A gslice of a const valarray:
valarray operator[](const gslice&) const; // copies of elements
//
...
5
...

valarray v0 {"abcdefghijklmnop",16};
valarray v1 {"ABCDE",5};
const valarray len {2,3};
const valarray str {7,2};
v0[gslice(3,len,str)] = v1;
// v0=={"abcAeBgCijDlEnFp",16}



A valarray (a mask) of a const valarray:
valarray operator[](const valarray&) const;
//
...

valarray v0 {"abcdefghijklmnop", 16};
valarray v1 {"ABC",3};
const bool vb[] {false, false, true, true, false, true};
v0[valarray(vb,6)] = v1;
// v0=={"abABeCghijklmnop",16}



A valarray (a set of indices) of a const valarray:
valarray operator[](const valarray&) const; // references to elements
//
...

valarray v0 {"abcdefghijklmnop",16};
valarray v1 {"ABCDE",5};
const size_t vi[] {7, 5, 2, 3, 8};
v0[valarray(vi,5)] {v1};
// v0=={"abCDeBgAEjklmnop",16}

Note that subscripting with a mask (a valarray) yields a
set of indices (a valarray) yields an indirect_array
...
5
...
swap(va2)
n=va
...
sum()
t=va
...
max()
va2=va
...
cshift(n)
va2=va
...
resize(n,t)
va
...
26
...
2
...
resize(n,T{})

There is no range checking: the effect of using a function that tries to access an element of an
empty valarray is undefined
...

v

valarray Operations (§iso
...
6
...
6, §iso
...
6
...
7)
or v2, but not both, can be a scalar; for arithmetic operations, the result is a valarray

swap(va,va2)
va3=va@va2
vb=v@v2
v2=@(v)
v3=atan2(v,v2)
v3=pow(v,v2)
p=begin(v)
p=end(v)

va
...
A scalar type is treated as a valarray of the right size with every element having the scalar’s
value
...
Naturally, an operation can be used only if the corresponding operation is defined for the scalar type
...


Section 40
...
3

Operations

1171

Where the result is a valarray, its length is the same as its valarray operand
...

These valarray operations return new valarrays rather than modifying their operands
...

For example, if v is a valarray, it can be scaled like this: v∗=0
...
3
...
As usual, ∗= is
more concise than a combination of ∗ and = (§18
...
1) and easier to optimize
...
For example:
double incr(double d) { return d+1; }
void f(valarray& v)
{
valarray v2 = v
...

}

// produce incremented valarray

This does not change the value of v
...
4
...
4) as an argument
...
For example, the cyclic shift v2=v
...
size()]
...
shift(n) produces a valarray
so that v3[i] is v[i+n] if i+n is a valid index for v
...

This implies that both shift() and cshift() shift left when given a positive argument and right when
given a negative argument
...
shift(2);
valarray v3 = v<<2;
valarray v4 = v
...
cshift(2);
valarray v7 = v
...

Consequently, <<= and >>= can be used to shift bits within elements of an integral type
...
5
...
5
...
5
...
5
...
However, an implementation is allowed to convert an operand that is
not a valarray to a valarray before performing a required operation
...
5
...
g
...
It is the key notion of Fortran
vectors and of the BLAS (Basic Linear Algebra Subprograms) library, which is the basis for much
numeric computation
...
Thus, a slice
describes a mapping of non-negative integers into indices
...
This mapping
can be used to simulate two-dimensional arrays within a one-dimensional array (such as valarray) in
an efficient, general, and reasonably convenient way
...
5
...
That is, the first element of row x is the x∗4th element of the
vector, the next element of the row is the (x∗4+1)th, etc
...
For
example, slice{0,4,1} describes the first row of v (row 0): 00, 01, 02, 03, and slice{1,4,1} describes the
second row (row 1)
...
That is, the first element of column y is the yth element of
the vector, the next element of the column is the (y+4)th, etc
...
For example, slice{0,3,4} describes the first column (column 0): 00, 10, 20, and slice{1,3,4}
describes the second column (column 1)
...
It is a fairly general way of specifying very simple sequences
...
5
...

One way of thinking of a slice is as an odd kind of iterator: a slice allows us to describe a
sequence of indices for a valarray
...
start()+i∗s
...
size()}; }
Slice_iter& operator++() { ++curr; return ∗this; }
Slice_iter operator++(int) { Slice_iter t = ∗this; ++curr; return t; }
T& operator[](size_t i) { return ref(i); }
T& operator()(size_t i) { return ref(i); }
T& operator∗() { return ref(curr); }

// C-style subscript
// Fortran-style subscript
// current element

bool operator==(const Slice_iter& q) const
{
return curr==q
...
stride()==q
...
stride() && s
...
s
...
curr && s
...
s
...
start()==q
...
start();
}
};

Since a

slice has a size, we could even provide range checking
...

Since a slice can describe either a row or a column, the Slice_iter allows us to traverse a valarray

by row or by column
...
5
...

slice_array
slice_array sa {sa2};
sa=sa2
sa=va
sa=v
sa@=va

(§iso
...
6
...
Instead, the user subscripts a valarray to create a
slice_array for a given slice
...
For example, we can create something that represents every second element of an array like this:
void f(valarray& d)
{
slice_array& v_even = d[slice(0,d
...
size()%2,2)];
slice_array& v_odd = d[slice(1,d
...
For example:

Section 40
...
5

slice_array

1175

slice_array row(valarray& d, int i)
{
slice_array v = d[slice(0,2,d
...

return d[slice(i%2,i,d
...
5
...
2
...
5
...
However,
sometimes we need to extract a subarray that is not a row or a column
...


};

The extra values allow a gslice to specify a mapping between n integers and an index to be used to
address elements of an array
...
start()+i∗s
...
stride()[1];
}

// max (i,j) to their corresponding index

1176

Numerics

Chapter 40

valarray lengths {2,3};// 2 elements in the first dimension
// 3 elements in the second dimension
valarray strides {3,1}; // 3 is the stride for the first index
// 1 is the stride for the second index
void f()
{
gslice s(0,lengths,strides);
for (int i=0; i<3; ++i)
// for each row
for (int j=0; j<2; ++j) // for each element in row
cout << "(" << i << "," << j << ")−>" << gslice_index(s,i,j) << "; ";

// print mapping

}

This prints:
(0,0)−>0; (0,1)−>1; (1,0)−>3; (1,1)−>4; (2,0)−>6; (2,1)−>7

In this way, a gslice with two (length,stride) pairs describes a subarray of a two-dimensional array,
a gslice with three (length,stride) pairs describes a subarray of a three-dimensional array, etc
...
For example:
void f(valarray<float>& v)
{
gslice m(0,lengths,strides);
v[m] = 0;
}

// assign 0 to v[0],v[1],v[3],v[4],v[6],v[7]

The gslice_array offers the same set of members as slice_array (§40
...
5)
...
5
...


40
...
These algorithms provide general versions
of common operations on sequences of numerical values:
Numerical Algorithms (§iso
...
7) (continues)
These algorithms take input iterators
x=accumulate(b,e,i)
x=accumulate(b,e,i,f)
x=inner_product(b,e,b2,i)

x=inner_product(b,e,b2,i,f,f2)

x is the sum of i and the elements of [b:e)
accumulate using f instead of +
x is the inner product of [b:e) and [b2:b2+(e−b)),
that is, the sum of i and (∗p1)∗(∗p2) for each p1 in [b:e)
and the corresponding p2 in [b2:b2+(e−b))
inner_product using f and f2 instead of + and ∗

Section 40
...
26
...


These algorithms generalize common operations such as computing a sum by letting them apply to
all kinds of sequences and by making the operation applied to elements of those sequences a
parameter
...


40
...
1 accumulate()
The simple version of accumulate() adds elements of a sequence using their + operator:
template
T accumulate(In first, In last, T init)
{
for (; first!=last; ++first) // for all elements in [first:last)
init = init + ∗first;
// plus
return init;
}

It can be used like this:
void f(vector& price, list<float>& incr)
{
int i = accumulate(price
...
end(),0);
double d = 0;
d = accumulate(incr
...
end(),d);

// accumulate in int
// accumulate in double

int prod = accumulate(price
...
end(),1,[](int a, int b) { return a∗b; });
//
...

We can provide an initial value and an operation for ‘‘combining elements’’ as arguments to
accumulate(), so accumulate() is not all about addition
...
For example:
struct Record {
//
...
unit_price ∗ r
...
begin(),v
...


40
...
2 inner_product()
Accumulating from a sequence is very common, and accumulating from a pair of sequences is not
uncommon:
template
T inner_product(In first, In last, In2 first2, T init)
{
while (first != last)
init = init + ∗first++ ∗ ∗first2++;
return init;
}
template
T inner_product(In first, In last, In2 first2, T init, BinOp op, BinOp2 op2)
{
while (first != last)
init = op(init,op2(∗first++,∗first2++));
return init;
}

As usual, only the beginning of the second input sequence is passed as an argument
...

The key operation in multiplying a Matrix by a valarray is an inner_product:
valarray operator∗(const Matrix& m, valarray& v)
{
valarray res(m
...
dim2(); i++) {
auto& ri = m
...
end(),&v[0],double(0));
}
return res;
}

Section 40
...
2

inner_product()

1179

valarray operator∗(valarray& v, const Matrix& m)
{
valarray res(m
...
dim1(); i++) {
auto& ci = m
...
end(),&v[0],double(0));
}
return res;
}

Some forms of inner_product are referred to as ‘‘dot product
...
6
...

Given a sequence a, b, c, d, etc
...

Consider a vector of temperature readings
...
begin(),temps
...
begin());
}

For example, 17, 19, 20, 20, 17 turns into 17, 2, 1, 0, −3
...
4)

1180

Numerics

Chapter 40

Given a sequence a, b, c, d, etc
...
For example:
void f()
{
partial_sum(temps
...
end(),temps
...
This allows res
to be the same sequence as the input; adjacent_difference() behaves similarly
...
begin(),v
...
begin());

turns the sequence a, b, c, d into a, a+b, a+b+c, a+b+c+d, and
adjacent_difference(v
...
end(),v
...
Thus, partial_sum() turns 17, 2, 1, 0, −3 back into 17, 19, 20, 20, 17
...
These operations are useful for analyzing any series of changes
...
6
...
For example:
vector v(5);
iota(v
...
end(),50);
vector v2 {50,51,52,53,54}
if (v!=v2)
error("complain to your library vendor");

The name iota is the Latin spelling of the Greek letter ι , which was used for that function in APL
...
2
...


40
...
For example, we might want to choose the TCP/IP address
for a router simulation, decide whether a monster should attack or scratch its head, or generate a set
of values for testing a square root function
...
These random numbers are sequences of values produced
according to mathematical formulas, rather than unguessable (‘‘truly random’’) numbers that could
be obtained from a physical process, such as radioactive decay or solar radiation
...
7
...

Four kinds of entities are provided:
• A uniform random number generator is a function object returning unsigned integer values
such that each value in the range of possible results has (ideally) equal probability of being
returned
...
7

Random Numbers

1181



A random number engine (an engine) is a uniform random number generator that can be
created with a default state E{} or with a state determined by a seed E{s}
...

• A random number distribution (a distribution) is a function object returning values that are
distributed according to an associated mathematical probability density function p(z) or
according to an associated discrete probability function P(zi)
...
26
...
1
...

The engine produces a uniformly distributed sequence of values, and the distribution bends those
into the desired shape (distribution)
...
For
example, binding a normal_distribution to the default_random_engine gives me a random number
generator that produces a normal distribution:
auto gen = bind(normal_distribution{15,4
...
5
...

Using ASCII graphics (§5
...
3), I got:
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

∗∗

∗∗∗∗∗
∗∗∗∗
∗∗∗∗
∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗∗∗∗∗∗
∗∗∗∗∗∗∗
∗∗∗∗∗
∗∗∗∗



1182

Numerics

Chapter 40

Most of the time, most programmers just need a simple uniform distribution of integers or floatingpoint numbers in a given range
...
5}; // uniform distribution of doubles in [0:0
...
7
...

Just for variation, I use a different technique for Rand_double:
class Rand_double {
public:
Rand_double(double low, double high)
:r(bind(uniform_real_distribution<>(low,high),default_random_engine())) { }
double operator()() { return r(); }
private:
function r;
};

One important use of random numbers is for sampling algorithms
...
Here is algorithm R (the simplest
algorithm) from a famous old paper [Vitter,1985]:
template
Out random_sample(Iter first, Iter last, Out result, Size n, Gen&& gen)
{
using Dist = uniform_int_distribution;
using Param = typename Dist::param_type;
// Fill the reservoir and advance first:
copy(first,n,result);
advance(first,n);

Section 40
...

// k increases with each iteration, making the probability smaller
...

Dist dist;
for (Size k = n; first!=last; ++first,++k) {
Size r = dist(gen,Param{0,k});
if(r < n)
∗(result + r) = ∗first;
}
return result;
}

40
...
1 Engines
A uniform random number generator is a function object that produces an approximately uniformly
distributed sequence of values of its result_type:
Uniform Random Number Generators: G (§iso
...
5
...
3)
G::result_type
x=g()
x=G::min()
x=G::max()

The type of an element of the sequence
Application operator: x is the next element of the sequence
x is the smallest element that a g() can return
x is the largest element that a g() can return

A random number engine is a uniform random number generator with additional properties to make
it widely useful:
Random Number Engines: E (§iso
...
5
...
4)
E e {};
E e {e2};
E e {s};
E e {g};
e
...
seed(s)
e
...
discard(n)
e==e2
e!=e2
os<is>>e

Default constructor
Copy constructor
e will be in a state determined by the seed s
e will be in a state determined by a call of generate() for the seed sequence g
e will be in the default state
e will be in a state determined by the seed s
e will be in a state determined by a call of generate() for the seed sequence g
Skip the next n elements of the sequence
Will e and e2 produce exactly the same sequences?
!(e==e2)

Write a representation of e to os
Read a representation of an engine previously written by << from is into e

A seed is a value in the range [0:232 ) that can be used to initialize a particular engine
...
generate(b,e) that when called fills [b:e) with
newly generated seeds (§iso
...
5
...
2)
...
26
...
3)
default_random_engine
linear_congruential_engine
mersenne_twister_engine
subtract_with_carry_engine

An alias for an engine with
wide applicability and low cost
x i+1 = (ax i + c) mod m
§iso
...
5
...
2
x i+1 = (ax i ) mod b
where b = m r − m s + 1
and a = b − (b − 1)/m

The UI parameter for a standard random number engine must be an unsigned integer type
...
For example, this writes out the index of the first repetition of a
number:
map m;
linear_congruential_engine linc_eng;
for (int i=0; i<1000000; ++i)
if (1<++m[linc_eng()]) cout << i << '\n';

I was lucky; the parameters were not too bad and I got no duplicate values
...
Use the default_random_engine unless you have a real
need and know what you are doing
...


int,16,5,0>

Standard Random Number Engine Adaptors (§iso
...
5
...
26
...
4
...
26
...
4
...
26
...
4
...

A few aliases are defined for useful engines:
using minstd_rand0 = linear_congruential_engine;
using minstd_rand = linear_congruential_engine;
using mt19937 = mersenne_twister_engine31,0x9908b0df,
11,0xffffffff,
7,0x9d2c5680,
15,0xefc60000,
18,1812433253>

Section 40
...
1

Engines

1185

using mt19937_64 = mersenne_twister_engine31,0xb5026f5aa96619e9,
29, 0x5555555555555555,
17, 0x71d67fffeda60000,
37, 0xfff7eee000000000,
43, 6364136223846793005>;
using ranlux24_base = subtract_with_carry_engine;
using ranlux48_base = subtract_with_carry_engine;
using ranlux24 = discard_block_engine;
using ranlux48 = discard_block_engine;
using knuth_b = shuffle_order_engine;

40
...
2 Random Device
If an implementation is able to offer a truly random number generator, that source of random numbers is presented as a uniform random number generator called random_device:
random_device
random_device rd {s};
d=rd
...
26
...
6)

The string s identifies a source of random numbers;
implementation-defined; explicit
d is a double; d==0
...
The entropy() is defined as
S(P 0 ,
...
, P n−1
...
In contrast to
thermodynamics, high entropy is good for random numbers because that means that it is hard to
guess subsequent numbers
...

The random_device is intended to be useful for cryptograpic applications, but it would be
against all rules of that kind of application to trust an implementation of random_device without
first studying it closely
...
7
...
26
...
1
...
26
...
1
...
reset()
p=d
...
param(p)
x=d(g)
x=d(g,p)
x=d
...
max()
d==d2
d!=d2
os<is>>d

Reset to default state
p is d’s parameters of param_type
Reset to the state determined by param_type p
x is a value produced by d given the generator g
x is a value produced by d given the generator g and the parameters p
x is the smallest value that d can return
x is the largest value that d can return
Will d and d2 produce identical sequences of elements?
!(d==d2)

Write d’s state to os so that it can be read back by >>
Read a state previously written by << from is into d

In the following tables, a template argument R means a real is required in the mathematical formula
and double is the default
...

Distribution

Uniform Distributions (§iso
...
5
...
2)
Precondition
Defaults

Result

uniform_int_distribution(a,b)

a≤b
(0,max)
P(i|a, b) = 1/(b − a + 1)

[a:b]

uniform_real_distribution(a,b)

a≤b
(0
...
0)
p(x|a, b) = 1/(b − a)

[a:b)

The precondition field specifies requirements on the distribution arguments
...
For example:
uniform_real_distribution urd1 {};
uniform_real_distribution urd2 {10,20};
uniform_real_distribution<> urd3 {};

// use a==0
...
0
// use a==10
...
0
// use double and a==0
...
0

The result field specifies the range of the results
...


Section 40
...
3

Distributions

1187

Bernoulli distributions reflect sequences of tosses of coins with varying degrees of loading:
Distribution

Bernoulli Distributions (§iso
...
5
...
3)
Precondition
Defaults

Result

bernoulli_distribution(p)

0<=p<1

(0
...
5)
⎛t ⎞ i
P(i|t, p) =
p (1 − p)t−i
⎝i ⎠

[0:∞)

geometric_distribution(p)

0< p<1
P(i| p) = p(1 − p)i

[0:∞)

negative_binomial_distribution(k,p)

0 < p < 1 and 0 < k
(1,0
...
5)

[0:∞)

Poisson distributions express the probability of a given number of events occurring in a fixed interval of time and/or space:
Distribution

Poisson Distributions (§iso
...
5
...
4)
Precondition
Defaults

Result

poisson_distribution(m)

0
(1
...
0)

(0:∞)

gamma_distribution(alpha,beta)

0 < α and 0 < β
(1
...
0)
e−x/ β
p(x|α , β ) = α
xα −1
β Γ(α )

weibull_distribution(a,b)

extreme_value_distribution(a,b)

e− μ μ i
P(i| μ ) =
i!

(0:∞)

0 < al and 0 < b
(1
...
0)
[0:∞)
a−1
a
a ⎛x⎞
x⎞ ⎞
⎛ ⎛
p(x|a, b) =
exp −
⎝ ⎝b⎠ ⎠
b ⎝b⎠
0
(0
...
0)
R
1
⎛a − x
⎛ a − x ⎞⎞
p(x|a, b) = exp
− exp
⎝ b
⎝ b ⎠⎠
b

Normal distributions map real values into real values
...
26
...
8
...
0,1
...
0,1
...
0,1
...

Such representations are easily generated and even more easily found on the Web
...
26
...
8
...
p n−1 ) = pi
The sequence [b:e) provides weights w i so
pi = w i /S and 0 < S = w 0 + ··· + w n?1
where n = e−b

Result
[0:e−b)

Section 40
...
3

Distribution

Distributions

Sampling Distributions (continued) (§iso
...
5
...
6)
Precondition
Defaults

discrete_distribution(lst)

1189

Result

discrete_distribution(lst
...
end())

discrete_distribution(n,min,max,f)

discrete_distribution(b,e)

where the ith element of [b:e) is obtained by
f(min+i∗(max?min)/n +(max−min)/(2∗n))
piecewise_constant_distribution{b,e,b2,e2}
piecewise_linear_distribution{b,e,b2,e2}

none
[∗b:∗(e−1))
P(x|x 0 ,
...
ρ n )
b[i]none
[∗b:∗(e−1))
P(x|x 0 ,
...
ρ n )
b −x
x − bi
+ ρi
= pi i+1
bi+1 − bi
bi+1 − bi
bi < bi+1 for all bi in [b:e)
1 n−1
ρ i = w i /S where S = Σ (w i + w i+1 )(bi+i − bi )
2 i=0
[b:e] are the interval boundaries
[b2:e2] are the weights
b[i]
40
...
4 C-Style Random Numbers
In and ...
In particular, the low-order bits of a random number are often suspect, so rand()%n is
not a good portable way of generating a random number between 0 and n−1
...
However, for serious applications, generators
based on uniform_int_distribution (§40
...
3) will give more reliable results
...

For debugging, it is often important that a sequence of random numbers from a given seed be
repeatable
...
In fact, to make games
unpredictable, it is often useful to pick a seed from the environment of a program
...


1190

Numerics

Chapter 40

40
...
If you are not 100% certain about the mathematical
aspects of a numerical problem, either take expert advice, experiment, or do both; §29
...

Use variants of numeric types that are appropriate for their use; §40
...

Use numeric_limits to check that the numeric types are adequate for their use; §40
...

Specialize numeric_limits for a user-defined numeric type; §40
...

Prefer numeric_limits over limit macros; §40
...
1
...
4
...
4
...
5
...
5
...

Slices is a generally useful abstraction for access of compact data; §40
...
4, §40
...
6
...
6
...
7
...
7
...

If you need genuinely random numbers (not just a pseudo-random sequence), use random_device; §40
...
2
...
7
...


41
Concurrency
Keep it simple:
as simple as possible,
but no simpler
...
Einstein







Introduction
Memory Model
Memory Location; Instruction Reordering; Memory Order; Data Races
Atomics
atomic Types; Flags and Fences
volatile

Advice

41
...

The C++ standard support for concurrency is introduced in a tutorial manner in §5
...
This
chapter and the next provide a more detailed and systematic view
...
A thread is the
system-level representation of a computer’s facilities for executing a task
...
2) can execute a task
...
That is,
all threads in a single address space can access the same memory locations
...

The standard library’s support for concurrency includes:

1192



Concurrency

Chapter 41

A memory model: a set of guarantees for concurrent access to memory (§41
...
3)
• A thread library: a set of components supporting traditional threads-and-locks-style systemlevel concurrent programming, such as thread, condition_variable, and mutex (§42
...
4)
These topics are ordered from the most fundamental and low-level to the highest-level
...
For programmer productivity and error minimization,
work at the highest feasible level
...
Leave the complexities to standard-library implementers whenever feasible
...

The topic of processes, that is, threads of execution in their own address spaces and communicating though inter-process communication mechanisms [Tanenbaum,2007], is not addressed in this
book
...
Naturally, communication implies some form of sharing, but that sharing most often need not be directly
managed by the application programmer
...
This is yet another reason to avoid global data
...
It provides:
• A basic description of the problems facing a programmer who has to deal with concurrency
at the system level
• A fairly detailed overview of the concurrency facilities provided by the standard
• An introduction to the basic uses of the standard-library concurrency features at the threadsand-locks level and above
It does not:
• Go into details of the relaxed memory models or lock-free programming
• Teach advanced concurrent programming and design techniques
Concurrent and parallel programming have been popular topics of research and widely used for
more than 40 years, so there is an extensive specialized literature (for example, for C++-based concurrency see [Wilson,1996])
...

In contrast to the C-style POSIX facilities and to many older C++ thread-support libraries, the
standard-library thread support is type-safe
...
Similarly, we can define tasks as function
objects (e
...
, lambdas) and pass them to threads without using casts or worrying about type violations
...
1

Introduction

1193

thread to another; futures (§5
...
5
...
4
...
Given that concurrent software is often complex and that code running in different threads is often separately developed, I
consider type safety and a standard (preferably exception-based) error-handling strategy even more
important than for single-threaded software
...


41
...
These
components rely on a set of language guarantees known as the memory model
...
The memory model, as specified in the ISO C++ standard, represents a
contract between the implementers and the programmers to ensure that most programmers do not
have to think about the details of modern computer hardware
...
Instead, the object is loaded into a
processor register, modified there, and then written back
...
For example, consider incrementing a simple integer x:
// add one to x:
load x into cache element Cx
load Cx into register Rx
Rx=Rx+1;
store Rx back into Cx
store Cx back into x

Memory can be shared by several threads, and cache memory may (depending on the machine
architecture) be shared among threads running on the same or different ‘‘processing units’’ (usually
called something like processors, cores, or hyper-threads; this is an area of rapid evolution of both
system facilities and terminology)
...
It will be obvious to machine architecture experts that I am
simplifying
...


41
...
1 Memory Location
Consider two global variables b and c:
// thread 1:
char c = 0;
void f()
{
c = 1;
int x = c;
}

// thread 2:
char b = 0;
void g()
{
b = 1;
int y = b;
}

Now, x==1 and y==1 as anyone would expect
...
At the same time, thread 2 could do the
same with b
...
We might get 10, 01, or
11 (but not 00)
...
The reason that 00 cannot happen is that the initializations of b and c are done (by the compiler or the linker) before either
thread starts
...
This is exactly what we would naively
expect
...
How a compiler and hardware combination achieves that is up to the compiler
...

Bit-fields (§8
...
7) give access to parts of a word
...
If b and c are two fields of the same word, most hardware
has no way of avoiding the problem (the race condition) from the b-and-c example without using
some form of (potentially very expensive) locking
...
Consequently, the language defines memory location as the unit of memory for which sensible behavior is
guaranteed to exclude individual bit-fields
...
2
...
For example:
struct S {
char a;
// location #1
int b:5;
// location #2
unsigned c:11;
unsigned :0;
// note: :0 is ‘‘special’’ (§8
...
7)
unsigned d:8;
// location #3
struct { int ee:8; } e; // location #4
};

Here, S has exactly four separate memory locations
...

From the explanation above, you might conclude that if x and y are of the same type, x=y is
guaranteed to result in x being a copy of y
...
2
...
However, if x and y are of a multiword struct they
are not a single memory location, and if you have a data race, all behavior is undefined, so make
sure you have proper synchronization in place if you share data (§41
...
3
...


Section 41
...
2

Instruction Reordering

1195

41
...
2 Instruction Reordering
To gain performance, compilers, optimizers, and hardware reorder instructions
...

}

For this piece of code there is no stated reason to assign to x before assigning to x_init
...

We probably meant for x_init to indicate whether x had been initialized by initializer() or not
...

Add another thread to the program:
// thread 2:
extern int x;
extern bool x_init;
void f2()
{
int y;
while (!x_init)
// if necessary, wait for initialization to complete
this_thread::sleep_for(milliseconds{10});
y = x;
//
...

Even if thread 1 did not set x_init and x in ‘‘the wrong order,’’ we still may have a problem
...


41
...
3 Memory Order
The time needed to get the value of a word from memory into a cache, then into a register, can be
(on a processor’s time scale) very long
...
The figure 500 is a guess that depends on machine architecture and varies over
time, but for the last decades it has steadily increased
...
A value can be ‘‘away from its location’’ for tens of thousands of instruction cycles
...
For example, my simplified description mentions only a single
cache; many popular architectures use a three-level cache
...
1
cache 2
...
1

core 3
core 4
cache 2
...
4
cache 1
...
The simplest memory order is called sequentially consistent
...
The order is as if the instructions were done sequentially in a single thread
...
An operation that ‘‘observes’’ a value
and thereby forces a consistent view of a memory location is called an atomic operation (see
§41
...
A simple read or write does not impose an order
...
Consider:
// thread 1:
char c = 0;
extern char b;
void f1()
{
c = 1;
int x = b;
}

// thread 2:
char b = 0;
extern char c;
void f2()
{
b = 1;
int y = c;
}

Assuming that the initialization of
three possible executions:
c = 1;
x = b;
b = 1;
y = c;

b = 1;
y = c;
c = 1;
x = b;

c

and

b

is done statically (before any thread starts), there are

c = 1;
b = 1;
x = b;
y = c;

The results are 01, 10, and 11, respectively
...
Obviously, to get a
predictable result, you need some form of synchronization of the access to the shared variables
...
For example, two threads running on separate cores might decide to initiate
the reads of x and y before the writes of a and b or at least before the writes had completed
...
More relaxed memory models allow that
...
2
...
2
...
But how? First, we must avoid data races
...
2
...
Note that defining ‘‘simultaneously’’ precisely is not trivial
...
This may sound drastic,
but the effects of a data race can (as shown in §41
...
2) be drastic
...

There are many ways of avoiding data races:
• Use only a single thread
...

• Put a lock on every data item that might conceivably be subject to a data race
...
Worse still, heavy use of locks
increases the chances of deadlock, where a thread waits for another forever, and other locking problems
...
This may
be the currently most popular approach, but it is error-prone
...
Programs that can do that for programs of commercial size and
complexity are not common
...

• Design the code so that threads communicate only through simple put-and-get-style interfaces that do not require two threads to directly manipulate a single memory location
(§5
...
5
...
4)
...
Examples include parallel implementations
of algorithms in a library, directive-based tools (e
...
, OpenMP), and transactional memory
(often abbreviated to TM)
...
In the process, we encounter the tools needed to support just about every way of avoiding data races
...
I can offer
two reasons:
[1] That is not the way the world is
...
Maybe someday machine architects will deliver simpler alternatives,
but for now someone must deal with a bewildering variety of low-level facilities provided
by machine architects to deliver the performance that their customers demand
...
We would have liked to
provide a memory model that was an improved version of what Java and C# provide
...
However, this idea was effectively vetoed by the providers of operating systems and virtual
machines: they insisted that they needed roughly what was then provided by the various
C++ implementations – what is now provided by the C++ standard
...
’’ I guess that programming language fanatics might have welcomed an
opportunity to simplify C++ at the expense of other languages, but doing so would have
been neither practical nor professional
...

Most programmers do not need to understand a memory model at all and can think of reordering
problems as amusing curiosities:
Write data-race-free code and don’t mess with memory order (§41
...
It’s even better than sequential consistency
...
g
...
Leave those for the experts and enjoy the higher levels that those experts provide for you
...
3 Atomics
Lock-free programming is a set of techniques for writing concurrent programs without using
explicit locks
...
2
...

Primitive operations that do not suffer data races, often called atomic operations, can then be used
in the implementation of higher-level concurrency mechanisms, such as locks, threads, and lockfree data structures
...

In addition to an understanding of language mechanisms, a detailed understanding of specific
machine architectures and a knowledge of somewhat specialized implementation techniques are
needed
...
The primary
logical advantage of lock-free techniques over lock-based techniques is that classical locking problems, such as deadlock and starvation, cannot happen
...
In addition, lock-free techniques can be significantly faster than
lock-based alternatives
...
Those typically either rely on assembly code or system-specific primitives
...

A synchronization operation is something that determines when a thread sees the effects of
another thread; it determines what is considered to have happened before something else
...
In principle, nobody is looking and all that is
affected is performance
...
3

Atomics

1199

consume operation, an acquire operation, a release operation, or both an acquire and release operation (§iso
...
10)
...

• For a release operation, other processors will see every preceding operation’s effect before
the effect of the operation itself
...
For a consume operation,
other processors will see its effect before any subsequent operation’s effect, except that
effects that do not depend on the consume operation’s value may happen before the consume operation
...
2
...
By default, the memory order is memory_order_seq_cst (sequentially consistent;
§41
...
2)
...
29
...

• memory_order_release, memory_order_acq_rel, and memory_order_seq_cst: A store operation
performs a release operation on the affected memory location
...

As an example, consider (§iso
...
3) using atomic loads and stores (§41
...
1) to express a relaxed
memory order:
// thread 1:
r1 = y
...
store(r1,memory_order_relaxed);
// thread 2:
r2 = x
...
store(42,memory_order_relaxed);

This is allowed to produce r2==42, making it appear that time went backward in thread 2
...
store(42,memory_order_relaxed);
r1 = y
...
store(r1,memory_order_relaxed);
r2 = x
...

It is entirely architecture-specific whether a given memory order makes sense
...
Utilizing
a relaxed memory model is an even more specialized task than general lock-free programming
...
It can also be useful in machine-generated code (as gotos can be)
...
g
...
4
...

To allow significant optimizations for architectures with relaxed memory models, the standard
provides an attribute [[carries_dependency]] for transmitting memory order dependencies across
function calls (§iso
...
6
...
For example:
[[carries_dependency]] struct foo∗ f(int i)
{
// let the caller use memory_order_consume for the result:
return foo_head[i]
...

One of the designers of the C++ memory model, Lawrence Crowl, summarizes:
‘‘Dependency ordering is probably the most complex concurrency feature
...

This is real expert territory
...

dency()

41
...
1 atomic Types
An atomic type is a specialization of the atomic template
...
That is, it is performed by a single thread without interference from other threads
...
, on a
simple object (usually a single memory location; §41
...
1)
...

The following tables aim to give a first impression and an overview (only)
...

x
...
29
...
val=T{}; constexpr
Constructor: x
...
3
...
val

Types

1201

atomic (continued) (§iso
...
5)
represents the value of the atomic x; all operations are noexcept

x=t
t=x
x
...
store(t)
x
...
load()
t=x
...
exchange(t)
t2=x
...
compare_exchange_weak(rt,t)
b=x
...
compare_exchange_weak(rt,t,order)
b=x
...
compare_exchange_strong(rt,t,order)
b=x
...
val=t
Implicit conversion to T: t=x
...
val=t
x
...
val
t=x
...
val==rt), x
...
val; rt is a T&
b=x
...
compare_exchange_weak(rt,t);
use order as the memory order (see §iso
...
6
...
compare_exchange_weak(rt,t,o1,o2)
Like b=x
...
compare_exchange_weak(rt,t)

There are no copy or move operations for atomics
...

A default atomic (without an explicit {}) is uninitialized to allow the C standard library to be
compatible
...
On all major implementations, is_lock_free() returns true
for integral and pointer types
...
Expect atomic
to be implemented using locks if T objects are large
...

The initialization of an atomic variable is not an atomic operation, so an initialization may have
a data race with an access from another thread (§iso
...
6
...
However, a data race with an initialization is quite hard to achieve
...

A simple atomic variable is close to ideal for a shared counter, such as a use count for a shared
data structure
...


1202

Concurrency

Chapter 41

˜shared_ptr()
{
if (−−∗puc) delete p;
}
private:
T∗ p;
// pointer to shared object
atomic∗ puc; // pointer to use count
};

Here, ∗puc is an atomic (allocated somewhere by a shared_ptr constructor), so that the decrement
operation (−−) is atomic and the new value is correctly reported in the thread destroying a
shared_ptr
...

The difference between compare_exchange_strong() and compare_exchange_weak() is that the
weak version can fail for ‘‘spurious reasons
...
compare_exchange_weak(rt,t) may cause a failure even if x
...
Allowing
such failures makes compare_exchange_weak() implementable on architectures where compare_exchange_strong() would be difficult or relatively expensive
...

int expected = val
...
compare_exchange_weak(expected,next)); // write next to val or to expected

The atomic val
...
If some other thread has written to val since we read it
in preparation to an update, we have to try again
...
Eventually, the expected value will be written
...
’’ So, since expected is
updated to the current value each time the compare_exchange_weak() is executed, we should never
get an infinite loop
...
There is a potentially serious problem with all CAS operations (in any language
and on any machine) known as the ABA problem
...
load();
// read the shared head of the list
do {
if (h−>data// if so, inser t elsewhere
nh−>next = h;
// next element is the previous head
} while (!head
...
3
...
I read the head, use it as the next of my new Link, and then write the pointer to my new Link to
head
...

Let us examine this code in some detail
...
If no other thread
changed the value of head before I executed my compare_exchange_weak(), it finds A in head and
succeeds in replacing it with my nh
...

This looks right
...
Then, some thread reused the node A
and reinserted it at the head of the list
...
However, the list had changed; the value of head went from A to B and then back to A
...
ABA problems can be very subtle
and hard to detect
...
I
mention it here primarily to warn about the subtleties of lock-free programming
...
val

atomic for Integral T (§iso
...
6
...
fetch_add(y)
z=x
...
val+=y; z is the previous x
...
fetch_add(y); use order

z=x
...
fetch_sub(y,order)
z=x
...
fetch_and(y,order)
z=x
...
fetch_or(y,order)
z=x
...
fetch_xor(y,order)

x
...
val
z=x
...
val&=y; z is the previous x
...
fetch_and(y); use order
x
...
val
z=x
...
valˆ=y; z is the previous x
...
fetch_xor(y); use order

++x
x++
−−x
x−−
x+=y
x−=y
x&=y
x|=y
xˆ=y

++x
...
val
x
...
val
−−x
...
val
x
...
val
x
...
val
x
...
val
x
...
val
x
...
val
x
...
val

Consider the popular double-checked locking idiom
...
Instead, you lock and initialize only if a variable
x_init is false:

1204

Concurrency

Chapter 41

X x;
mutex lx;
atomic x_init {false};

// we need a lock to initialize an X
// the mutex to be used to lock x during initialization
// an atomic used to minimize locking

void some_code()
{
if (!x_init) {
// proceed if x is uninitialized
lx
...
initialize x
...
unlock();
}
//
...

}

Had init_x not been atomic, instruction reordering could have moved the initialization of x ahead of
the apparently unrelated test of init_x (see §41
...
2)
...

The !x_init relies on the implicit conversion from an atomic to a T
...
3
...
4)
...
3
...

The standard library also supports atomic pointers:
x
...
29
...
4)
represents the value of the atomic x; all operations are noexcept

z=x
...
fetch_add(y,order)
z=x
...
fetch_sub(y,order)

x
...
val
z=x
...
val−=y; z is the previous x
...
fetch_sub(y); use order

++x
x++
−−x
x−−
x+=y
x−=y

++x
...
val
x
...
val
−−x
...
val
x
...
val
x
...
val
x
...
val

To allow the C standard library to be compatible, the atomic member function types have freestanding equivalents:
atomic_∗

operations (§iso
...
6
...
3
...
29
...
5)
All operations are noexcept

atomic_store(p,v)
x=atomic_load(p)
x=atomic_load(p)
b=atomic_compare_exchange_weak(p,q,v)

Store v in ∗p
Assign ∗p to x
Load ∗p into x
Compare and exchange ∗p and ∗q; b=(∗q==v)


...


41
...
2 Flags and Fences
In addition to the support for atomic types, the standard library offers two lower-level synchronization facilities: atomic flags and fences
...
They are the only lock-free mechanisms
that are guaranteed to be supported on every implementation (though all major platforms support
atomic types)
...
Those who do usually work closely
with machine architects
...
3
...
1 atomic Flags
An atomic_flag is the simplest atomic type and the only one with operations guaranteed to be
atomic for every implementation
...
If necessary, the other atomic types can be implemented using atomic_flag
...

atomic_flag (§iso
...
7)
All operations are noexcept
atomic_flag fl;
atomic_flag fl {};
atomic_flag fl {ATOMIC_FLAG_INIT};
b=fl
...
test_and_set(order)

...
clear(order)
b=atomic_flag_test_and_set(flp)
b=atomic_flag_test_and_set_explicit(flp,order)
atomic_flag_clear(flp)
atomic_flag_clear_explicit(flp,order)

The value of fl is undefined
Default construct: the value of fl is 0
Initialize fl to clear
Set fl and b is fl’s old value
Set fl and b is fl’s old value;
use memory order order
Clear fl
Clear fl; use memory order order
Set ∗flp; b is ∗flp’s old value
Set ∗flp; b is ∗flp’s old value;
use memory order order
Clear ∗flp
Clear ∗flp;
use memory order order

The bool return values are true for set and false for clear
...
However, there is no guarantee that 0
represents clear
...
Clearing using ATOMIC_FLAG_INIT
is the only portable and reliable way of initializing an atomic_flag
...

You can think of an atomic_flag as a very simple spin lock:
class spin_mutex {
atomic_flag flag = ATOMIC_FLAG_INIT;
public:
void lock() { while(flag
...
clear(); }
};

Note that spin locks can easily become very expensive
...


41
...
2
...
2
...
The fence operations do not do anything else
...

Fences (§iso
...
8)
All operations are noexcept
atomic_thread_fence(order)
atomic_signal_fence(order)

Enforce memory order order
Enforce memory order order
for a thread and a signal handler executed on that thread

Fences are used in combination with atomics (needed to observe the effects of the fences)
...
4 volatile
The volatile specifier is used to indicate that an object can be modified by something external to the
thread of control
...
For example:
auto t1 {clock_register};
//
...

auto t2 {clock_register};

Had clock_register not been volatile, the compiler would have been perfectly entitled to eliminate
one of the reads and assume t1==t2
...


Section 41
...
It does not
...
To get synchronization, use an atomic
(§41
...
3
...
3
...


41
...
1
...
1
...
1
...
1
...
1
...
1
...
1
...
2
...
2
...
2
...
2
...

Atomics allow for lock-free programming; §41
...

Lock-free programming can be essential for avoiding deadlock and to ensure that every
thread makes progress; §41
...

Leave lock-free programming to experts; §41
...

Leave relaxed memory models to experts; §41
...

A volatile tells the compiler that the value of an object can be changed by something that is
not part of the program; §41
...

A C++ volatile is not a synchronization mechanism; §41
...


This page intentionally left blank

42
Threads and Tasks
Keep Calm and Carry On
...
1 Introduction
Concurrency – the execution of several tasks simultaneously – is widely used to improve throughput (by using several processors for a single computation) or to improve responsiveness (by allowing one part of a program to progress while another is waiting for a response)
...
3
...

We call an activity potentially executed concurrently with other activities a task
...
A thread can execute a
task
...
That is, all threads in a single
address space can access the same memory locations
...


1210

Threads and Tasks

Chapter 42

42
...
The C++ standardlibrary threads are intended to map one-to-one with the operating system’s threads
...
On a system with several processing units (‘‘cores’’), threads allows us to use those units
...
If you want hardware protection against data races, use some notion of a process
...
In particular, beware of by-reference context bindings in lambdas (§11
...
3)
...

If a thread cannot proceed (e
...
, because it has encountered a mutex owned by another thread), it
is said to be blocked or asleep
...
˜thread();
t=move(t2)
t
...
joinable()
t
...
detach()
x=t
...
native_handle()
n=hardware_concurrency()
swap(t,t2)

(§iso
...
3
...
30
...
3)
Default constructor: create a thread that does not
(yet) have a task; noexcept
Move constructor; noexcept
Constructor: execute f(args) on a new thread; explicit
Destructor: if t
...
joinable(), then terminate(); noexcept
Exchange the values of t and t2; noexcept
Is there a thread of execution associated with t?
t
...
g
...
get_id()==this_thread::get_id());
throw system_error if t
...
id!=id{}
x is the id of t; noexcept
x is the native handle for t (of native_handle_type)
n is the number of hardware processing units
(0 means ‘‘don’t know’’); noexcept
t
...
2

Threads

1211

thread

system thread

Consequently, a thread can be moved but not copied
...
In particular, it cannot be join()ed
...
The exact meaning of that is architecture-dependent, but it is
usually less than the number of threads offered by the operating system (e
...
, through time multiplexing or time slicing) and sometimes higher than the number of processors or ‘‘cores
...


42
...
1 Identity
Each thread of execution has a unique identifier represented as a value of type thread::id
...
The id of a thread t can be
obtained by a call of t
...

The id of the current thread can be obtained by this_thread::get_id() (§42
...
6)
...

Every thread has an id, but a system thread may still be running even though it does not have an id
(i
...
, after a detach())
...
), output using <<, and hashed with a specialization hash (§31
...
3
...
For example:
void print_id(thread& t)
{
if (t
...
get_id() << '\n';
}

Note that cout is a global shared object so that those output statements are not guaranteed to produce output characters in a recognizable sequence unless you make sure that no two threads are
writing to cout at the same time (§iso
...
4
...


1212

Threads and Tasks

Chapter 42

42
...
2 Construction
A thread constructor takes a task to be executed and the arguments required by that task
...
For example:
void f0();
void f1(int);

// no arguments
// one int argument

thread t1 {f0};
thread t2 {f0,1};
thread t3 {f1};
thread t4 {f1,1};
thread t5 {f1,1,2};
thread t3 {f1,"I'm being silly"};

// error : too many arguments
// error : too few arguments
// error : too many arguments
// error : wrong type of argument

After construction, a thread starts executing its task as soon as the run-time system can acquire
resources for it to run
...
’’ There is no separate ‘‘start the thread’’
operation
...
g
...
For example:
template
class Sync_queue { // a queue providing put() and get() without data races (§42
...
4)
//
...


Trying to intersperse thread creation with the setup of connections among the tasks to be run by the
threads can easily become complicated and error-prone
...
2
...
6)
...
5
...
For example:

thread

void my_task(vector& arg);
void test(vector& v)
{
thread my_thread1 {my_task,v};
thread my_thread2 {my_task,ref(v)};
thread my_thread3 {[&v]{ my_task(v); }};
//
...
So, if v was {1,2,3} and my_task increments
elements, thread1 would never have any effect on v
...

A default-constructed thread is primarily useful as the target for a move
...
size(); ++i) {
//
...

worker[i] = move(tmp);
}

Moving a task from one thread to another does not affect its execution
...


thread

move simply

42
...
3 Destruction
Obviously, the thread destructor destroys the thread object
...
For example:
void heartbeat()
{
while(true) {
output(steady_clock::now());
this_thread::sleep_for(second{1}); // §42
...
6
}
}
void run()
{
thread t {heartbeat};
}
// terminate because heartbeat() is still running at the end of t’s scope

If you really need to have a system thread proceed beyond the lifetime of its thread see §42
...
5
...
2
...
join() tells the current thread not to proceed until t completes
...
2
...
join();
}

This will output Alive! ten times at about 1-second intervals
...
join() been missing, the
program would have terminated before tick() could have printed anything
...

As mentioned in §42
...
3, trying to have a thread execute past the end of its scope (or more generally, after its destructor is run) without calling detach() is considered a fatal (for the program)
error
...
When we view a thread as a resource, we see that
we should consider RAII (§5
...
3)
...

if (ithread t3 {g};
//
...

t1
...
join();
}

Here, I have made several bad mistakes
...
In that case, the destructor for t1 will terminate the program
...
In
that case, t2
...

For this kind of thread use, we need a destructor that implicitly join()s
...
2
...
joinable()) t
...
3
...
1

guarded_thread is not a standard-library class, but in the best RAII tradition
makes our code shorter and less error-prone
...

if (ithread t3 {g};
//
...

}

But why doesn’t the thread’s destructor just join()? There is a long-standing tradition of using system threads that ‘‘live forever’’ or decide for themselves when to terminate
...
2
...
Threads monitoring
data structures provide many more examples
...
Another use for detached threads is to simply initiate a thread to complete a task and forget
about it
...


42
...
5 detach()
Accidentally letting a thread try to execute beyond its destructor is considered a very bad error
...
For example:
void run2()
{
thread t {heartbeat};
t
...
Given a choice, I would prefer to
• know exactly which threads are running,
• be able to determine if threads are making progress as expected,
• be able to check if threads that are supposed to delete themselves really do so,
• be able to know whether it is safe to use the results of a thread,
• be sure that all resources associated with a thread are properly released, and
• be sure that a thread does not try to access objects from the scope in which it was created
after that scope has been destroyed
...
g
...
Also, how do I debug a system where the behavior of
detached threads cannot be directly observed? What happens if a detached thread holds a pointer to
something in the scope in which it was created? That could lead to corrupted data, a system crash,
or a security violation
...
After all,
people have been doing it for decades
...
Given a choice, I prefer not to detach() threads
...
This allows threads to
migrate out of the scope in which they were constructed and often provides an alternative to
detach()
...
g
...
For example:
vector my_threads; // keep otherwise detached threads here
void run()
{
thread t {heartbeat};
my_threads
...

my_threads
...
get_id() << '\n';
}

For a more realistic example, I would associate some information with each thread in my_threads
...

If you must use a detach() a thread, do make sure that it does not refer to variables in its scope
...
3});++var; }}
disaster
...
It is not:
the system thread invoked by disaster() will ‘‘forever’’ keep writing to the address where home()’s
var was allocated, corrupting any data that may later be allocated there
...

Such bugs have been called Heisenbugs in honor of the discoverer of the uncertainty principle
...
1
...
However, with a lambda, it is

Section 42
...
5

detach()

1217

easy (and almost invisible) to create a pointer to a local variable: [&]
...


42
...
6 Namespace this_thread
Operations for the current thread are found in namespace this_thread:
Namespace this_thread (§iso
...
3
...
For example:
void helper(thread& t)
{
thread::id me {this_thread::get_id()};
//
...
get_id()!=me) t
...

}

Similarly, we can use this_thread::sleep_until(tp) and this_thread::sleep_for(d) to put the current
thread to sleep
...
The current thread is
not blocked, so it will eventually be run again without any other thread having to do anything specific to wake it
...
Usually, it is better to use sleep_for(n) than to just yield()
...
Consider yield() a feature for optimization in very rare and specialized cases
...
However, for historical and language technical reasons, preemption is only encouraged rather than required by the
standard (§iso
...
10)
...
But if a clock is reset (say, because
it has drifted from the true time), a wait_until() would be affected, but not a wait_for()
...
3
...
3)
...
2
...
There is no simple standard way of telling a
running thread that I have lost interest in its task, so would it please stop running and release all its
resources
...
4
...
There are various historical and technical reasons for the lack
of this operation (called kill, cancel, and interrupt in various languages and systems)
...
For example,
many tasks involve a request loop
...
If there is no request loop, a task
could periodically examine a ‘‘needed’’ variable to see if results are still wanted
...


42
...
8 thread_local Data
As indicated by its name, a thread_local variable is an object owned by a thread and not accessible
from other threads unless its owner (incautiously) gives them a pointer to it
...
A thread_local object can be extern
...
As usual, namespaces can be
used to limit the problems with nonlocal data
...

A thread_local is said to have thread storage duration (§iso
...
7
...
Each thread has its own copy
of its thread_local variables
...
3
...
If constructed, it will be destroyed on thread exit
...
That can complicate the program logic, but on machines with shared caches it
can sometimes deliver very significant performance advantages
...

In general, nonlocal memory is a problem for concurrent programming because it is often nontrivial to determine if it is shared and thus a possible source of data races
...
Consider a Map design with a per-type default value:
template
class Map {
public:
Map();
//
...
2
...


Section 42
...
8

thread_local

Data

1219

One-per-class (static) values used to be popular
...
When used in a
concurrent system, we have a classic problem:
// somewhere in thread 1:
Map::set_default("Heraclides",1);
// somewhere in thread 2:
Map::set_default("Zeno",1);

This is a potential data race: which thread gets to first execute set_default()?
Adding thread_local helps:
template
class Map {
//
...
However, there is no longer a single default_value
shared among all users either
...
As often as not, that was not what was intended in the original code, so by adding
thread_local, we simply exchanged one error for another
...

A namespace variable, a local static, and a class static member can be declared thread_local
...
3
...
The order of construction of thread_locals is undefined, so keep the construction
of different thread_locals independent of their order and use compile-time or link-time initialization
whenever possible
...
3
...
1)
...
3 Avoiding Data Races
The best way to avoid data races is not to share data
...
2
...
Do not pass pointers
to such data to other threads
...
g
...

These simple rules are based on the idea of avoiding attempts to simultaneously access data, so
they don’t require locking and lead to maximally efficient programs
...
To access the resource, acquire the mutex, access, and then
release the mutex (§5
...
4, §42
...
1)
...
3
...
1, §42
...
4)
...
Rather, they save us from having to
introduce shared data that might become a source of data races
...
3
...
Thus, it can be used to
protect against data races and to synchronize access to data shared between multiple threads
...
30
...
In exchange for added functionality, recursive and timed mutexes carry a small cost, which may or may not be significant for a given
application on a given machine
...

• To release a mutex means relinquishing exclusive ownership; a release operation will allow
another thread to eventually acquire the mutex
...

If several threads are blocked on a mutex the system scheduler could in principle select the thread to
be unblocked in such a way that some unfortunate thread would never get to run
...
For example, a scheduler might always choose the thread with
the highest thread::id to run next, thereby starving a thread with a low id
...
’’ That is, they make it extremely
unlikely that a thread starves forever
...

By itself, a mutex doesn’t do anything
...

We use ownership of a mutex to represent the right to manipulate a resource, such as an object,
some data, or an I/O device
...
3
...
lock();
cout << "From thread " << name << " : " << a1 << a2 << a3;
cout_mutex
...
The snag is
that every thread has to use a mutex as intended
...
In the cout_mutex example, a thread using cout directly (bypassing
cout_mutex) can corrupt output
...

Note that I locked the mutex only for the one statement that required the lock
...
A section of code protected by a lock is called a
critical section
...

The standard-library mutexes provide exclusive ownership semantics
...
There are other kinds of mutexes
...

If you need a different kind of mutex, use one offered by a specific system or write it yourself
...
3
...
1 mutex and recursive_mutex
Class mutex offers a simple set of operations:
mutex
mutex m {};
m
...
lock()
m
...
unlock()
native_handle_type
nh=m
...
30
...
1
...
1)

Default constructor: m is not owned by any thread; constexpr; noexcept
Destructor: undefined behavior if owned
Acquire m; block until ownership is acquired
Try to acquire m; did acquisition succeed?
Release m
An implementation-defined system mutex type
nh is the system handle for the mutex m

A mutex cannot be copied or moved
...
In fact, a mutex is typically implemented as a handle to a system resource, but since that
system resource cannot be shared, leaked, copied, or moved, it is usually a spurious complication to
think of them as separate
...
For example:
mutex cout_mutex; // initialized to ‘‘not owned by any thread’’
void hello()
{
cout_mutex
...
unlock();
}

1222

Threads and Tasks

Chapter 42

void world()
{
cout_mutex
...
unlock();
}
int main()
{
thread t1 {hello};
thread t2 {world};
t1
...
join();
}

Given that, we will get the output
Hello, World!

or
World! Hello,

We will not get cout corrupted or some mixed-up output characters
...
As an example, consider a work generator that composes work
requests for other tasks and places them on a work queue:
extern mutex wqm;
extern list wq;
void composer()
{
list requests;
while (true) {
for (int i=0; i!=10; ++i) {
Work w;
//
...

requests
...
try_lock()) {
wq
...
4
...
unlock();
}
}
}

When some server
of waiting
...
3
...
1

mutex

and recursive_mutex

1223

When using locks, we have to beware of deadlock
...
The simplest form of deadlock requires only one lock and one thread
...
Args>
void write(Arg a, Args tail
...
lock();
cout << a;
write(tail
...
unlock();
}

Now, if a thread calls write("Hello,","World!"), it will deadlock with itself when it tries the recursive
call for the tail
...
A recursive_mutex is just like a plain mutex, except that a single thread can acquire it repeatedly
...
Args>
void write(Arg a, Args tail
...
lock();
cout << a;
write(tail
...
unlock();
}

Now the recursive call of write() is correctly handled by cout_mutex
...
3
...
2 mutex Errors
Trying to manipulate a mutex can fail
...


Some of

Mutex Error Conditions (§iso
...
4
...
2)
resource_deadlock_would_occur
resource_unavailable_try_again
operation_not_permitted
device_or_resource_busy
invalid_argument

For example:

A deadlock would occur
Some native handle is not available
The thread is not allowed to perform the operation
Some native handle is already locked
A constructor native handle argument is bad

1224

Threads and Tasks

Chapter 42

mutex mtx;
try {
mtx
...
lock();
// try to lock a second time
}
catch (system_error& e) {
mtx
...
what() << '\n';
cout << e
...
3
...
4)
...
3
...
3 timed_mutex and recursive_timed_mutex
A simple mtx
...
If we don’t want to block, we can use mtx
...
The timed_mutex and
recursive_timed_mutex offer support for that:
timed_mutex
timed_mutex m {};
m
...
lock()
m
...
try_lock_for(d)
m
...
unlock()
native_handle_type
nh=m
...
30
...
1
...
1)

Default constructor; m is not owned; constexpr; noexcept
Destructor: undefined behavior if owned
Acquire m; block until ownership is acquired
Try to acquire m; did the acquisition succeed?
Try to acquire m for a maximum duration of d;
did the acquisition succeed?
Try to acquire m until time_point tp at the latest;
did the acquisition succeed?
Release m
Implementation-defined system mutex type
nh is the system handle for the mutex

The recursive_timed_mutex interface is identical to the timed_mutex interface (just as the recursive_mutex interface is identical to the mutex interface)
...
2
...
More
generally, we can m
...
try_lock_for(d) for a timed_mutex m
...

As an example, consider updating an output buffer with a new image (e
...
, in a video game or a
visualization):
extern timed_mutex imtx;
extern Image buf;

Section 42
...
1
...
compute
...
try_lock(milliseconds{100})) {
buf = next_image;
imtx
...
Further, it is assumed that missing an
image in a sequence of updated images will rarely be noticed, so that a more complicated solution
is not needed
...
3
...
4 lock_guard and unique_lock
A lock is a resource, so we must not forget to release it
...
lock() operation must be
matched by an m
...
The usual opportunities for mistakes exist; for example:
void use(mutex& mtx, Vector& vs, int i)
{
mtx
...

mtx
...
unlock() is there, but if i<0 or if i is out of vs’s range and vs is range checked, the thread of
execution never gets to the mtx
...

The standard library provides two RAII classes, lock_guard and unique_lock, to handle such
problems
...
In exchange for added functionality, unique_ptr carries a small cost, which may or may not be significant for a given application on a given machine
...
30
...
2)
m is a lockable object
lock_guard lck {m};
lock_guard lck {m,adopt_lock_t};
lck
...

}

The lock_guard’s destructor does the necessary unlock() on its argument
...
Obviously, the checking of i does not require locking, so we could do
that before acquiring the lock:
void use(mutex& mtx, vector& vs, int i)
{
if (i<0) return;
lock_guard g {mtx};
string s = vs[i];
//
...


Then, we could put the

void use(mutex& mtx, vector& vs, int i)
{
if (i<0) return;
string s;
{
lock_guard g {mtx};
s = vs[i];
}
//
...
’’ we
cannot tell, but we should definitely not use a lock_guard just out of unwillingness to consider
where locking is needed
...

If nothing else, it forces us to think about exactly where a lock is needed and why
...


lock_guard

lockable object

Section 42
...
1
...
The obvious lockable object is of a standard-library
mutex type, but users can define their own
...
All it does is RAII for a
mutex
...
30
...
2)
m is a lockable object
unique_lock lck {};
unique_lock lck {m};
unique_lock lck {m,defer_lock_t};
unique_lock lck {m,try_to_lock_t};
unique_lock lck {m,adopt_lock_t};
unique_lock lck {m,tp};
unique_lock lck {m,d};
unique_lock lck {lck2};
lck
...
lock()
lck
...
try_lock_for(d)
lck
...
unlock()
lck
...
release()
lck
...
mutex()
swap(lck,lck2)

Default constructor: lck does not hold a mutex;
noexcept
lck acquires m; explicit
lck holds m but does not acquire it
lck holds m and does a m
...
try_lock_until(tp);
if the try succeeds, lck owns m; otherwise not
lck holds m and calls m
...
lock()
m
...
try_lock_for(d); did acquisition succeed?
m
...
unlock()
Exchange the lockable objects of lck and lck2;

noexcept
lck no longer owns ∗pm; noexcept
Does lck own a lockable object? noexcept
Conversion to bool; b==lck
...
swap(lck2); noexcept

Obviously, the timed operations are only allowed if the contained mutex is a timed_mutex or a recursive_timed_mutex
...
try_lock_for(milliseconds{2});

// error : mutex does not have member try_lock_for()

lck2
...
try_lock_until(steady_clock::now()+milliseconds{2});
//
...
The owns_lock() operations allow us to check whether such
an acquisition succeeded
...
owns_lock()) {
// acquisition succeeded:
//
...

}
else {
// timeout:
//
...

}
}

42
...
2 Multiple Locks
It is fairly common to want to acquire multiple resources to do some task
...
For example:
mutex mtx1;
mutex mtx2;

// protects one resource
// protects another resource

void task(mutex& m1, mutex& m2)
{
unique_lock lck1 {m1};
unique_lock lck2 {m2};
//
...

}

Section 42
...
2

Multiple Locks

1229

thread t1 {task,ref(mtx1),ref(mtx2)};
thread t2 {task,ref(mtx2),ref(mtx1)};

The ref() is the std::ref() reference wrapper from (§33
...
It is needed to pass a reference through a variadic template (the thread constructor; §42
...
2)
...

Change the names from mtx1 and mtx2 to something that does not indicate order and separate
the definitions of t1 and t2 from each other in the source text and it will no longer be obvious that
there is a good chance that the program will eventually deadlock with t1 owning mtx1, t2 owning
mtx2, and each trying to acquire its second mutex forever
...
30
...
2)
is a sequence of one or more lockable objects lck1, lck2, lck3,
...
Mx>
int try_lock(M1& mtx, Mx& tail
...
try_lock()) {
int n = try_lock(tail
...
unlock();
// back out
return n+1;
}
return 1;
// couldn’t acquire mtx
}
template
int try_lock(M1& mtx)
{
return (mtx
...
use resources
...


1230

Threads and Tasks

Chapter 42

42
...
3 call_once()
We often want to initialize an object without getting into a race condition
...

call_once
once_flag fl {};
call_once(fl,f,args)

(§iso
...
4
...

private:
//
...

Run-time initialization of a local static variable is implemented by call_once() or by a mechanism very similar to call_once()
...
3
...


Section 42
...
4

Condition Variables

1231

42
...
4 Condition Variables
Condition variables are used to manage communication among threads
...

condition_variable (§iso
...
5)
lck must be a unique_lock
condition_variable cv {};
cv
...
notify_one()
cv
...
wait(lck)

cv
...
wait_until(lck,tp)

Default constructor: throw a system_error
if some system resource cannot be obtained
Destructor: no thread may be waiting and not notified
Unblock one waiting thread (if any); noexcept
Unblock all waiting threads; noexcept
lck must be owned by the calling thread;
atomically calls lck
...
lock()
lck must be owned by the calling thread;
while (!pred()) wait(lock);
lck must be owned by the calling thread;
atomically calls lck
...
lock();
x is timeout if it timed out; otherwise x=no_timeout

x=cv
...
wait_for(lck,d,pred)

while (!pred()) if (wait_until(lck,tp)==cv_status::timeout);
b=pred()
x=cv
...
wait_until(lck,steady_clock::now()+d,move(pred))

native_handle_type
nh=cv
...
30
...
3
nh is the system handle for cv

b=cv
...
However, like a mutex, a condition_variable cannot be copied or moved, so it is
best to think of a condition_variable as a resource in itself, rather than as a handle
...
e
...

The status returned by wait_until() and wait_for() is defined as:
enum class cv_status { no_timeout, timeout };

A condition_variable’s unique_lock is used by the wait functions to prevent wake-ups being lost due
to contention on the unique_lock’s list of waiting threads
...
It can wake up ‘‘spuriously
...
Always use ‘‘plain’’ wait() in a loop
...
empty()) wait(queue_lck);

An additional reason for this loop is that some thread may have ‘‘snuck up’’ and invalidated the
condition (here, queue
...
Such a
loop basically is the implementation of a wait with a condition, so prefer those over the unconditional wait()
...
wait_for(lck,milliseconds{delay}); // release and reacquire mtx
auto t1 = steady_clock::now();
cout << duration_cast(t1−t0)
...
The mutex protects wait_for()
against data races
...
Finally, lck (implicitly) releases the mutex at the end of its scope
...
A thread that does a get() will sleep
unless there is a value on the queue for it to get
...
push_back(val);
cond
...
3
...
I provided an
rvalue version of put() so that we can transmit objects of types that have move, but not copy, operations, such as unique_ptr (§5
...
1, §34
...
1) and packaged_task (§42
...
3)
...
The possibility of multiple consumers and the possibility of consumers falling behind
the producer might make me reconsider
...
wait(lck,[this]{ return !q
...
front();
q
...

I used a unique_lock rather than a plain lock_guard because the lock_guard is optimized for simplicity and does not offer the operations needed to unlock and relock the mutex
...
4
...
3)
...
That is the
conventional technique (e
...
, the STL stack adaptor provides pop() and the containers provide
front())
...
For
an example, see future::get() (§42
...
4)
...
fill m
...
put(m);
}
}
void consumer()
{
while (true) {
Message m;
mq
...
use m
...
Had we simply used a mutex to control access to the Sync_queue, the consumer would have had to repeatedly wake up, look for work on the queue, and decide what to do
when it found the queue empty
...
A copy of an element
type may throw an exception, but if it does, the Sync_queue will remain unchanged and the put() or
get() simply fails
...

For some applications, the simple Sync_queue has a fatal flaw: What if a consumer waits forever
because a producer stopped adding values? What if a consumer has other things to do so that it
cannot wait for a long time? Often there are answers, but one common technique is to add a timeout to get(), that is, to specify a maximum time to wait:
void consumer()
{
while (true) {
Message m;
mq
...
use m
...
wait_for(lck,d,[this]{ return !q
...
front();
q
...
I chose to report the failure of a get() with a timeout by throwing an exception
...


Section 42
...
4

Condition Variables

1235

The roughly equivalent modification to put() would be to wait for the consumer to make inroads
into a long queue, but not for too long a time:
template
void Sync_queue::put(T val, steady_clock::duration d, int n)
{
unique_lock lck(mtx);
bool not_full = cond
...
size()if (not_full) {
q
...
notify_one();
}
else {
cond
...
However, to avoid getting into a discussion of how
best to handle overflow, I again chose to signal a failure by throwing an exception
...
Maybe, some consumer needs a nudge to continue
...
Notifying just one thread serializes access to the queue and could therefore
minimize throughput when there are several potential consumers
...
I fall back on
the old rule: Don’t trust your intuition; measure
...
3
...
1 condition_variable_any
A condition_variable is optimized for unique_lock
...
30
...
2)
can be any lockable object with the operations required


...


42
...
For many concurrent tasks, I find this
focus on mechanisms distracting from the real task (sic!) of specifying concurrent tasks
...


1236

Threads and Tasks

Chapter 42

To support this task-based model of concurrency, the standard library offers:
Task Support (§iso
...
6
...
Please keep in mind the fundamental simplicity of the task model
...

The standard-library task support is just one example of what can be done to support task-based
concurrency
...

The importance of these facilities is their simplicity to a programmer
...
do something else
...
get()

// perform a task given arguments
// get the result

Sometimes, we lose sight of the value of simplicity as we consider alternatives, details, performance, and tradeoffs
...


42
...
1 future and promise
As mentioned in §5
...
5, communication between tasks is handled by a future/promise pair
...
30
...
4)
...
4
...
At a minimum, a shared state must be able to hold:
• A value of the appropriate type or an exception
...

• A ready bit to indicate whether a value or exception is ready to be extracted by a future
...
4
...

• A use count, so that the shared state can be destroyed when and only when its last potential
user relinquishes access
...

• Some mutual exclusion data to enable unblocking of any thread that might be waiting (e
...
,
a condition_variable)
...

• Make ready: Set the ‘‘ready bit’’ and unblock any waiting threads
...

• Abandon: If it becomes impossible for a value or exception to be put into the shared state by
a promise (e
...
, because the promise is destroyed), a future_error exception with the error
condition broken_promise is stored in the shared state and the shared state is made ready
...
4
...
4
...
It is where a task can deposit its result to be
retrieved through a future (§42
...
4)
...
˜promise()
pr2=move(pr)
pr
...
get_future()
pr
...
set_value()
pr
...
30
...
5) (continues)
Default constructor: pr has a shared state
that is not yet ready
Construct pr; use allocator a
to construct a shared state that is not yet ready
Move constructor: pr gets pr2’s state;
pr2 no longer has a shared state; noexcept
Destructor: abandon the shared state;
make the result a broken_promise exception
...
set_value_at_thread_exit(x)
pr
...
30
...
5)
The result of the task is the value x;
don’t make the result ready until thread exit
The result of the task is the exception
pointed to by p; p is an exception_ptr;
don’t make the result ready until thread exit
pr
...

A set function throws future_error if a value or exception is already set
...
That may seem restrictive, but remember that the value is moved into and out of the shared state, rather than copied, so
that we can cheaply pass a collection of objects
...
fill m with a million pairs
...
set_value(m);

A task may then extract that map from a corresponding future at essentially zero cost
...
4
...

packaged_task:

task 2:

task 1:
set_value(x)
future

return x

set_exception(px)

get()

throw x

promise

value
We pass a task (a function or a function object) that we want executed to a packaged_task
...
Similarly, a
throw x causes a set_exception(px) where px is an exception_ptr for x
...
set_value(f(args));
// assume that the promise is called pr
}
catch(
...
set_exception(current_exception());
}

A packaged_task offers a fairly conventional set of operations:

Section 42
...
3

packaged_task

packaged_task ...
30
...
9)

pt
...
swap(pt2)
true_type if PT

packaged_task pt {};
packaged_task pt {f};
packaged_task pt {allocator_arg_t,a,f};
packaged_task pt {pt2};
pt=move(pt2)

pt
...
swap(pt2)
pt
...
get_future()
pt()(args)

pt
...
A packaged_task may copy its task, and a copy of a
task is assumed to yield the same result as the original
...

To abandon a shared state (as is done by the destructor and the move) means making it ready
...
4
...

The advantage of make_ready_at_exit() is that the result is not available until destructors for
thread_local variables have been executed
...
The use of the promise is completely
handled by the packaged_task
...
First define a simple task:
int ff(int i)
{
if (i) return i;
throw runtime_error("ff(0)");
}

We can now package this function into packaged_tasks and call them:

1240

Threads and Tasks

Chapter 42

packaged_task pt1 {ff};
packaged_task pt2 {ff};
pt1(1);
pt2(0);

// store ff in pt1
// store ff in pt2

// let pt1 call ff(1);
// let pt2 call ff(0);

So far, nothing appears to have happened
...
In fact, pt1(1) did a set_value(1) on the promise attached to pt1, and pt1(0) did a set_exception(px) on the promise attached to pt2; that px is an exception_ptr to a runtime_error("ff(0)")
...
The get_future() operation is used to get hold of the
future into which the packaged thread will deposit the result of its task
...
get_future();
auto v2 = pt2
...
get() << '\n';
cout << v2
...
what() << '\n';
}

The output is:
1
exception: ff(0)

We could have gotten exactly the same effect by simply writing:
try {
cout << ff(1) << '\n'; // will print
cout << ff(0) << '\n'; // will throw
}
catch (exception& e) {
cout << "exception: " << e
...
We
can concentrate on specifying the tasks, rather than thinking about threads and locks
...
Eventually, the packaged_task is
invoked and its task deposits its result in the future without having to know either which thread
executed it or which thread will receive the result
...

Consider a thread that processes a series of requests
...
We can implement such a service as a queue of messages (§42
...
4), or we could
pass tasks to be executed:
using Res = /* result type for server */;
using Args = /* argument types for server */;

Section 42
...
3

packaged_task

1241

using PTT = Res(Args);
Sync_queue> server;
Res f(Args);
struct G {
Res operator()(Args);
//
...
get_future();
auto f2 = job2
...
get_future();
server
...
put(move(job2));
server
...
get();
auto r2 = f2
...
get();

The server thread would take the packaged_tasks from the server queue and execute them in some
suitable order
...

The tasks are written essentially like ordinary functions, function objects, and lambdas
...
The packaged_tasks are actually
easier for the server to use than ordinary functions because the handling of their exceptions has
been taken care of
...
4
...
4
...
It is where a task can retrieve a result deposited by
a promise (§42
...
2)
...
˜future()
fu=move(fu2)

(§iso
...
6
...
share()
x=fu
...
get()
fu
...
wait()
fs=fu
...
wait_until(tp)

(continued) (§iso
...
6
...
get(), but don’t move any value
Is fu valid? that is, does fu have a shared state? noexcept
Block until a value arrives
Block until a value arrives or for a duration d;
fs tells if a value is ready, a timeout occurred, or execution was deferred
Block until a value arrives or until a time_point tp;
fs tells if a value is ready, a timeout occurred, or execution was deferred

A future holds a unique value and offers no copy operations
...
So get() can only be called once
...
g
...
4
...

It is undefined what happens if you try to get() twice
...

The standard ‘‘encourages’’ an implementation to throw a future_error with the error condition
future_errc::no_state in such cases
...

• future::get() returns a T&
...

The status of a future can be observed by calling wait_for() and wait_until():
enum class future_status
ready
timeout
deferred

The future has a value
The operation timed out
The execution of the future’s task is deferred until a get()

The possible errors from operations on futures are:
future
broken_promise
future_already_retrieved
promise_already_satisfied
no_state

Errors: future_errc

A promise abandoned the state before supplying a value
A second get() on a future
A second set_value() or set_exception() on a promise()
An operation tried to access a promise’s shared state
before that state was created (e
...
, get_future() or set_value())

In addition, an operation on the T value of shared_future::get() could possibly throw (e
...
, an
unusual move operation)
...

• wait_for_any(args): Wait until one future in args has a value
...
4
...
push_back(fu
...
Ideally, my thread would be blocked and unblocked at most once
...
On the other hand, if all tasks are short, they will most likely
have finished after the first wait
...
First we need a way of checking if a future is
ready
...
For example:
future_status s = fu
...
It is common, but unfortunately not guaranteed, that wait_for(seconds{0}) returns immediately rather than trying to suspend for zero time
...
size(); ++i) {
if (!vf[i]
...
wait_for(seconds{0})) {
case future_status::ready:
return i;
case future_status::timeout:
break;
case future_status::deferred:
throw runtime_error("wait_for_all(): deferred future");
}
}
this_thread::sleep_for(d);
}
}

I decided to consider a deferred task (§42
...
6) an error for my uses
...
Trying wait_for() on an invalid future (e
...
, a future on which you have
already done a get()) will cause a hard-to-find error
...


1244

Threads and Tasks

Chapter 42

Like the implementation of wait_for_all(), this implementation has a flaw: ideally, the caller of
should never have to wake up just to find that no tasks had completed and should be
unblocked immediately when one does
...
With
a large d a useless wake-up is unlikely but implies the possibility of an unnecessarily long wait
...
I use them in §42
...
6
...
4
...
Thus, if you want to read the value
repeatedly or potentially have it read by multiple readers, you must copy it, and then read the copy
...
Every usable shared_future is directly or indirectly initialized by
moving the value out of a future with the same result type
...
˜future()
sf=sf2
sf=move(sf2)
x=sf
...
get()
sf
...
wait()
fs=sf
...
wait_until(tp)

(§iso
...
6
...
get()
but doesn’t copy any value
Does sf have a shared state? noexcept
Block until a value arrives
Block until a value arrives or for a duration d;
fs tells if a value is ready, a timeout occurred,
or execution was deferred
Block until a value arrives or until a time_point tp;
fs tells if a value is ready, a timeout occurred,
or execution was deferred

Obviously, shared_future is very similar to future
...
As for future, special rules
apply for get() when a shared_future’s value type, T, is void or a reference:
• shared_future::get() doesn’t return a value: it just returns or throws an exception
...
A reference isn’t an object, so the library must have
transmitted something else, such as a T∗, and get() converts that (back) into a T&
...

Unless the returned object is a reference, it is const, so it can safely be accessed from several
threads without synchronization
...


Section 42
...
6

async()

1245

42
...
6 async()
Given future and promise (§42
...
1) and packaged_task (§42
...
3), we can write simple tasks without
worrying too much about threads
...

However, we still need to consider how many threads to use and whether a task is best run on the
current thread or on another
...

Asynchronous Task Launcher: async() (§iso
...
6
...
A call
of async() returns a future where R is the type of its task’s result
...
get();

If a thread is launched to execute square(2), we may have a record slow way of executing 2∗2
...
get();

In principle, a caller of async() could provide a huge variety of information to help the implementation of async() decide whether to launch a new thread, rather than simply executing the task on the
current thread
...
However, only two policies are currently standard:
Launch Policies: launch
async
deferred

Execute the task as if a new thread was created to do so
Execute the task at the point of a get() for the task’s future

Note the as if
...
For example, since the default policy is async|deferred (async or deferred), it is not
too fanciful to imagine an async() that decided to use deferred for async(square,2), so that the execution reduced to fd
...
I could even imagine an optimizer reducing that whole
code fragment to
double d = 4;

However, we should not expect an implementation of async() to be optimized for such trivial examples
...


1246

Threads and Tasks

Chapter 42

By a ‘‘recycled thread’’ I mean a thread from a collection of threads (a thread pool) that async()
may create once and use over and over to execute a variety of tasks
...
If a thread
is recycled, the launcher must take care that a task does not see leftover state from a previous task
executed on the thread and that a task does not store pointers to its stack or thread_local data
(§42
...
8) in nonlocal storage
...

A simple and realistic use of async() would be to spawn a task to collect input from a user:
void user()
{
auto handle = async([](){ return input_interaction_manager(); });
//
...
get();
//
...
I used a lambda to make it obvious that I can
pass arguments or allow access to local variables
...
That could lead to data races or unfortunate cache access
patterns by two threads accessing the same stack frame
...
4
...
3) implies that the members of the object are accessed indirectly
(through this), rather than copied, so that the object is subject to data races unless you make certain
that it is not
...

It is often important that we can select a scheduling policy ‘‘late’’ and change it as needed
...
That would eliminate errors related to
concurrency until I had eliminated sequential errors
...

Over time, more launch policies may become available, and maybe some systems offer better
launch policies than others
...

This, again, is an effect of the fundamental simplicity of the task-based model (§42
...

Having launch::async|launch::deferred as the default launch policy can be a practical problem
...
An implementation might decide
that ‘‘no concurrency’’ is a good idea and always use launch::deferred
...


42
...
7 A Parallel find() Example
A find() does a linear search of a sequence
...
This could be slow, so instead of
searching once starting at the beginning and going until the end, we might start 100 find()s each on
a hundredth of the data
...
4
...
begin()+first,vr
...
begin()+last)
return nullptr;
// at end: no record found
return &∗p;
// found: return a pointer to the element
}

Unfortunately, we have to decide on a ‘‘grain’’ of parallelism
...

const int grain = 50000;

// number of records for a linear search

Picking a number like that is a very primitive way of choosing a grain size
...
Experimentation is essential
...
However, for a simple illustration of basic standardlibrary facilities and the most basic techniques for their use, grain is sufficient
...
Then, it get()s the results:
template
Record∗ pfind(vector& vr, Pred pr)
{
assert(vr
...
size(); i+=grain)
res
...
size(); ++i)
if (auto p = res[i]
...
size()%grain==0);
Record∗ p = pfind(goods,
[](Record& r) { return r
...
color==Color::red; });
cout << "record "<< ∗p << '\n';
}

1248

Threads and Tasks

Chapter 42

This first version of a parallel find() first spawns a lot of tasks and then proceeds to wait for them in
order
...
That may be fine, but:
• We could end up waiting for a lot of tasks that don’t find anything (maybe only the last task
finds something)
...

The first problem may not be as bad as it sounds
...
That is, we would potentially get our result in the time taken to examine 50,000 records rather than millions
...
If no record
is found until the last segment of the vector, the time will be roughly vr
...

Instead of waiting for each task in order, we could try to look at the results in the order the tasks
completed
...
4
...
For example:
template
Record∗ pfind_any(vector& vr, Pred pr)
{
vector> res;
for (int i = 0; i!=vr
...
push_back(async(find_rec,ref(vr),i,i+grain,pr));
for (int count = res
...
get())
return p;
}
return nullptr;

// find a completed task
// did the task find a match?

// no match found

}

A get() renders its future invalid, so we don’t get to look at a partial result twice
...
Apart from
that, pfind_any() is as simple as pfind()
...
Like find_if(), pfind() returns its
first match, whereas pfind_any() returns whichever match it first found
...

In this case, the obvious question is ‘‘But do you really only need one match?’’ Given concurrency, it makes more sense to find all matches
...
All we need to do is to let each
task return a vector of matches, rather than just a simple match:

Section 42
...
7

A Parallel find() Example

1249

template
vector find_all_rec(vector& vr, int first, int last, Pred pr)
{
vector res;
for (int i=first; i!=last; ++i)
if (pr(vr[i]))
res
...

Now we just need to launch find_all_rec() a suitable number of times and wait for the results:
template
vector pfind_all(vector& vr, Pred pr)
{
vector>> res;
for (int i = 0; i!=vr
...
push_back(async(find_all_rec,ref(vr),i,i+grain,pr));
vector> r2 = wait_for_all(res);
vector r;
for (auto& x : r2)
for (auto p : x)
r
...
However, by merging the vectors returned into a single one, pfind_all()
became an example of a common and popular group of parallel algorithms:
[1] Create a number of tasks to be run
...

[3] Merge the results
...

The example can be run like this:
void find_all_cheap_red()
{
assert(goods
...
price<200 && r
...
To do so, I added simple
sequential versions to my test:
void just_find_cheap_red()
{
auto p = find_if(goods
...
end(),
[](Record& r) { return r
...
color==Color::red; });
if (p!=goods
...
size(),
[](Record& r) { return r
...
color==Color::red; });
for (auto p : vp)
cout << "record "<< ∗p << '\n';
}

For my simple test data and my (relatively) simple laptop with only four hardware threads, I did not
find any consistent or significant performance differences
...
If I needed significant parallel speedup right now, I would implement my own variant of async() based on a pre-created set of threads and a work queue, along the lines of a Sync_queue (§42
...
4) of packaged_tasks
(§42
...
3)
...
From the application’s point of view, replacing the standard-library async()
with an optimized version is an implementation detail
...
5 Advice
[1]
[2]
[3]
[4]
[5]
[6]
[7]
[8]
[9]

A thread is a type-safe interface to a system thread; §42
...

Do not destroy a running thread; §42
...
2
...
2
...

Consider using a guarded_thread to provide RAII for threads; §42
...
4
...
2
...

Use lock_guard or unique_lock to manage mutexes; §42
...
1
...

Use lock() to acquire multiple locks; §42
...
2
...
3
...

Think in terms of tasks that can be executed concurrently, rather than directly in terms of
threads; §42
...

[10] Value simplicity; §42
...

[11] Return a result using a promise and get a result from a future; §42
...
1
...
4
...


Section 42
...
4
...

[14] Use a packaged_task and a future to express a request to an external service and wait for its
response; §42
...
3
...
4
...

[16] Use async() to launch simple tasks; §42
...
6
...
4
...

[18] Whenever possible, hide concurrency behind the interface of a parallel algorithm; §42
...
7
...
g
...
find()); §42
...
7
...
4
...


This page intentionally left blank

43
The C Standard Library
C is a strongly typed,
weakly checked language
...
M
...

Advice

43
...
The C standard library provides quite a few functions that have proven useful over
the years in a wide variety of contexts – especially for relatively low-level programming
...


43
...
A file (a FILE∗) can refer to a file or to one of the standard
input and output streams: stdin, stdout, and stderr
...
If that is a problem (is considered a leak), use an fstream (§38
...
1)
...
For example, x is sometimes
used to mean ‘‘the file must not exist before this open operation
...
The I/O modes
should be the same for stdio and iostreams (§38
...
1)
...
3 The printf() Family
The most popular C standard library functions are the output functions
...
The formatted output function, printf(), is
widely used (also in C++ programs) and widely imitated in other programming languages:
printf()
n=printf(fmt,args)
n=fprintf(f,fmt,args)
n=sprintf(s,fmt,args)

Print the format string fmt to stdout,
inserting the arguments args as appropriate
Print the format string fmt to file f,
inserting the arguments args as appropriate
Print the format string fmt to the C-style string s,
inserting the arguments args as appropriate

For each version, n is the number of characters written or a negative number if the output failed
...

The declaration of printf() is:
int printf(const char∗ format
...
The meaning of those ‘‘extra arguments’’ is controlled by

Section 43
...
For example:

The printf() Family

%c

(print as character) and

%d

1255

(print as decimal integer), in the

int x = 5;
const char∗ p = "Pedersen";
printf("the value of x is '%d' and the value of s is '%s'\n",x,s);

A character following a % controls the handling of an argument
...
In particular, the output of that call to printf() is
the value of x is '5' and the value of s is 'Pedersen'

followed by a newline
...
For example:
printf("the value of x is '%s' and the value of s is '%x'\n",x,s);

// oops

The set of conversion specifications is quite large (and growing over the years) and provides a great
degree of flexibility
...

See also the set of options used for strftime() formatting (§43
...
Following the %, there may be:

an optional minus sign that specifies left-adjustment of the converted value in the field;
+
an optional plus sign that specifies that a value of a signed type will always begin with a +
or − sign;
0
an optional zero that specifies that leading zeros are used for padding of a numeric value
...

an optional period that serves to separate the field width from the next digit string;
d
an optional digit string specifying a precision that specifies the number of digits to appear
after the decimal point, for e- and f-conversion, or the maximum number of characters to
be printed from a string;

a field width or precision may be ∗ instead of a digit string
...
The conversion characters
and their meanings are:
d
The integer argument is converted to decimal notation;
i
The integer argument is converted to decimal notation;
o
The integer argument is converted to octal notation;
x
The integer argument is converted to hexadecimal notation;
X
The integer argument is converted to hexadecimal notation;
f
The float or double argument is converted to decimal notation in the style [−]ddd
...

The number of d’s after the decimal point is equal to the precision for the argument
...
If the precision is missing, six digits are given; if
the precision is explicitly 0 and # isn’t specified, no decimal point is printed;
F
Like %f but uses capital letters for INF, INFINITY, and NAN
...
ddde+dd or [−]d
...
If necessary, the number is rounded
...
hhhhp+d or
[−]0xh
...
Null characters are ignored;
s
The argument is taken to be a string (character pointer), and characters from the string
are printed until a null character or until the number of characters indicated by the
precision specification is reached; however, if the precision is 0 or missing, all characters up to a null are printed;
p
The argument is taken to be a pointer
...


Section 43
...

Here is a more elaborate example:
char∗ line_format = "#line %d \"%s\"\n";
int line = 13;
char∗ file_name = "C++/main
...
c"

Using printf() is unsafe in the sense that type checking is not done
...

Because C does not have user-defined types in the sense that C++ has, there are no provisions
for defining output formats for user-defined types, such as complex, vector, or string
...
6) is an example of the contortions you can get into by trying to design yet
another set of format specifiers
...
The C standard input, stdin, corresponds to
cin
...
This correspondence between C standard I/O and C++ I/O streams is so close that C-style I/O and I/O streams can share a buffer
...
This flexibility carries a cost
...
To ensure that, call
ios_base::sync_with_stdio(false) before the first I/O operation (§38
...
4)
...
For example:
int x;
char s[buf_size];
int i = scanf("the value of x is '%d' and the value of s is '%s'\n",&x,s);

Here, scanf() tries to read an integer into x and a sequence of non-whitespace characters into s
...
For example:
the value of x is '123' and the value of s is 'string '\n"

will read 123 into x and string followed by a 0 into s
...
This way of specifying input is error-prone (e
...
, what would happen if
you forgot the space after string on that input line?)
...
I

1258

The C Standard Library

Chapter 43

strongly recommend against the use of scanf()
...
If an end-of-file is encountered or if an error occurred, p
is set to the nullptr; otherwise, it is set to s
...
The sprintf() function can suffer similar buffer-overflow problems
...
As for iostream’s unformatted
input, that leaves the user with the problem of deciding exactly which termination condition was
encountered (§38
...
1
...
g
...

The stdio library also provides simple and useful character read and write functions:
Stdio Character Functions
x=getc(st)
x=putc(c,st)
x=getchar()
x=putchar(c)
x=ungetc(c,st)

Read a character from input stream st;
x is the character’s integer value or EOF if end-of-file or an error occurred
Write the character c to the output stream st;
x is the integer value of the character written or EOF if an error occurred
x=getc(stdin)
x=putc(c,stdout)
Put c back onto the input stream st;
x is the integer value of c or EOF if an

error occurred

The result of these operations is an int (not a char, or EOF could not be returned)
...
The result of that is undefined and non-portable
...
g
...


43
...
This notion of a string is supported by a set of
functions defined in (or ...
These functions
operate on C-style strings through char∗ pointers (const char∗ pointers for memory that is only read,
but not unsigned char∗ pointers):

Section 43
...
See also §36
...
2, §36
...
3, and §36
...
7
...
See also §36
...
5
...
3) if their result doesn’t fit into

43
...
, does not invoke constructors and free() doesn’t invoke destructors
...
Also, memset() should never be used
for any type with a constructor
...
For example:
int max = 1024;
char∗ p = static_cast(malloc(max));
char∗ current_word = nullptr;
bool in_word = false;
int i=0;
while (cin
...

}

// double allocation

I hope you spotted the nasty bug: if realloc() was called, current_word may (may not) point to a location outside the current allocation pointed to by p
...
5

Memory

1261

Most uses of realloc() are better done using a vector (§31
...
1)
...


43
...
For values t1 and t2 returned by clock(), double(t2−t1)/CLOCKS_PER_SEC is the system’s best
approximation of the time in seconds between the two calls
...
2
...

The strftime() function uses a printf() format string to control the output of a tm
...
6

Date and Time

Date and Time Formatting
%a
%A
%b
%B
%c
%C
%d
%D
%e
%F
%g
%G
%h
%H
%I
%j
%m
%M
%n
%p
%r
%R
%S
%t
%T
%u
%U
%V
%w
%W
%x
%X
%y
%Y
%z
%Z
%%

Abbreviated weekday name
Full weekday name
Abbreviated month name
Full month name
Date and time representation
The year divided by 100 and truncated to a decimal integer [00:99]
The day of the month as a decimal number [01:31]
Equivalent to %m/%d/%y
The day of the month as a decimal number [1:31];
a single digit is preceded by a space
Equivalent to %Y−%m−%d; the ISO 8601 date format
The last two digits of the week-based year as a decimal number [00:99]
The week-based year as a decimal number (e
...
, 2012)
Equivalent to %b
The hour (24-hour clock) as a decimal number [00:23]
The hour (12-hour clock) as a decimal number [01:12]
The day of the year as a decimal number [001:366]
The month as a decimal number [01:12]
The minute as a decimal number [00:59]
A newline character
The locale’s equivalent of AM/PM for a 12-hour clock
12-hour clock time
Equivalent to %H:%M
The second as a decimal number [00:60]
A horizontal-tab character
Equivalent to %H:%M:%S; the ISO 8601 time format
The ISO 8601 weekday as a decimal number [1:7]; Monday is 1
The week number of the year (the first Sunday is the first day of week 1)
as a decimal number [00:53]
The ISO 8601 week number as a decimal number [01:53]
The weekday as a decimal number [0:6]; Sunday is 0
The week number of the year (the first Monday is the first day of week 1)
as a decimal number [00:53]
The locale’s appropriate date representation
The locale’s appropriate time representation
The last 2 digits of the year as a decimal number [00:99]
The year as a decimal number (e
...
, 2012)
The offset from UTC in the ISO 8601 format −0430 (4
...


1263

1264

The C Standard Library

Chapter 43

Some conversion specifiers can be modified by an E or O modifier, indicating alternative implementation-specific and locale-specific formatting
...
4
...
1)
...
2
...
7 Etc
...
...
The integer returned is
• Negative if ∗p is considered less than ∗q
• Zero if ∗p is considered equal to ∗q
• Positive if ∗p is considered greater than ∗q
This differs from sort(), which uses a conventional <
...
If you want destructors called for constructed objects, throw an exception (§13
...
1)
...
It does not invoke destructors
...
Never use setjmp() in a
C++ program
...
7

Etc
...

In , we find int_fast16_t and other standard integer aliases:
Integer Type Aliases
N can be 8, 16, 32, or 64
int_N_t
uint_N_t
int_leastN_t
uint_leastN_t
int_fastN_t
uint_leastN_t

Integer type of N bytes, e
...
int_8_t
Unsigned integer type of N bytes, e
...
, uint_16_t
Integer type of at least N bytes, e
...
, int_least16_t
Unsigned integer type of at least N bytes, e
...
, uint_least32_t
Integer type of at least N bytes, e
...
, int_fast32_t
Unsigned integer type of at least N bytes, e
...
, uint_fast64_t

Also in , we find type aliases for the largest signed and unsigned integer types for an
implementation
...
8 Advice
[1]
[2]
[3]
[4]

Use fstreams rather than fopen()/fclose() if you worry about resource leaks; §43
...

Prefer to for reasons of type safety and extensibility; §43
...

Never use gets() or scanf("%s",s); §43
...

Prefer to for reasons of ease of use and simplicity of resource management;
§43
...

[5] Use the C memory management routines, such as memcpy(), only for raw memory; §43
...

[6] Prefer vector to uses of malloc() and realloc(); §43
...

[7] Beware that the C standard library does not know about constructors and destructors; §43
...

[8] Prefer to for timing; §43
...

[9] For flexibility, ease of use, and performance, prefer sort() over qsort(); §43
...

[10] Don’t use exit(); instead, throw an exception; §43
...

[11] Don’t use longjmp(); instead, throw an exception; §43
...


This page intentionally left blank

44
Compatibility
You go ahead and follow your customs,
and I´ll follow mine
...
Napier








Introduction
C++11 Extensions
Language Features; Standard-Library Components; Deprecated Features; Coping with Older
C++ Implementations
C/C++ Compatibility
C and C++ Are Siblings; ‘‘Silent’’ Differences; C Code That Is Not C++; C++ Code That Is
Not C
Advice

44
...
The purposes are
• To concisely list what is new in C++11
• To document differences that can cause problems for a programmer
• To point to ways of dealing with problems
Most compatibility problems surface when people try to upgrade a C program to a C++ program,
try to port a C++ program from an older version of C++ to a newer one (e
...
, C++98 to C++11), or
try to compile C++ using modern features with an older compiler
...

When you look at compatibility issues, a key question to consider is the range of implementations under which a program needs to work
...
For delivering a product, a more conservative strategy might
be in order to maximize the number of systems on which the product can run
...
However,
implementations are converging, so the need for portability across platforms is less cause for
extreme caution than it once was
...
2 C++11 Extensions
First, I list the language features and standard-library components that have been added to C++ for
the C++11 standard
...


44
...
1 Language Features
Looking at a list of language features can be quite bewildering
...
In particular, most features that are new in C++11 make no
sense in isolation from the framework provided by older features
...
2
...
3
...
2
...
3
...
1)
[3] Prevention of narrowing (§2
...
2, §6
...
5)
[4] Generalized and guaranteed constant expressions: constexpr (§2
...
3, §10
...
1
...
2
...
5
...
2
...
2
...
3
...
4
...
4
...
3, §24
...
2
...
3, §17
...
4)
[10] Rvalue references (enabling move semantics; §3
...
2, §7
...
2)
[11] Nested template arguments ending with >> (no space between the >s; §3
...
1)
[12] Lambdas (§3
...
3, §11
...
4
...
6)
[14] Type and template aliases (§3
...
5, §6
...
6)
[15] Unicode characters (§6
...
3
...
3
...
2)
[16] long long integer type (§6
...
4)
[17] Alignment controls: alignas and alignof (§6
...
9)
[18] The ability to use the type of an expression as a type in a declaration: decltype (§6
...
6
...
3
...
1)
[20] Generalized POD (§8
...
6)
[21] Generalized unions (§8
...
1)
[22] Local classes as template arguments (§11
...
2, §25
...
1)
[23] Suffix return type syntax (§12
...
4)
[24] A syntax for attributes and two standard attributes: [[carries_dependency]] (§41
...
1
...
5
...
1)

Section 44
...
1

Language Features

1269

[26] Testing for the possibility of a throw in an expression: the noexcept operator (§13
...
1
...
e
...
2
...
6
...
6
...
6)
[28] inline namespaces (§14
...
6)
[29] Delegating constructors (§17
...
3)
[30] In-class member initializers (§17
...
4)
[31] Control of defaults: default (§17
...
6
...
4
...
2
...
2
...
2
...
1)
[36] Inheriting constructors (§20
...
5
...
3
...
5
...
2)
[39] Memory model (§41
...
2
...
A historical perspective on these
features can be found in §1
...


44
...
2 Standard_Library Components
The C++11 additions to the standard library come in two forms: new components (such as the regular expression matching library) and improvements to C++98 components (such as move constructors for containers)
...
2
...
3, §17
...
4, §31
...
2)
[2] Move semantics for containers (§3
...
1, §17
...
2, §31
...
2)
[3] A singly-linked list: forward_list (§4
...
5, §31
...
2)
[4] Hash containers: unordered_map, unordered_multimap, unordered_set, and unordered_multiset (§4
...
5, §31
...
3)
[5] Resource management pointers: unique_ptr, shared_ptr, and weak_ptr (§5
...
1, §34
...
3
...
2), mutexes (§5
...
4, §42
...
1), locks (§5
...
4,
§42
...
2), and condition variables (§5
...
4
...
3
...
3
...
4)
[8] tuples (§5
...
3, §28
...
2
...
2)
[9] Regular expressions: regex (§5
...

(§5
...
3, §40
...
2
...
7)
[12] A fixed-sized contiguous sequence container: array (§8
...
4, §34
...
1)
[13] Copying and rethrowing exceptions (§30
...
1
...
4
...
3
...
5)
[19] string to numeric value conversions (§36
...
5)
[20] Scoped allocators (§34
...
4)
[21] Type traits, such as is_integral and is_base_of (§35
...
2)
[23] Compile-time rational arithmetic: ratio (§35
...
4
...
5)
[27] Low-level concurrency support: atomics (§41
...
6), string (§19
...
5)
• The emerging specialized C++11 standard-library literature, such as [Williams,2012]
• A brief historical perspective can be found in §1
...


44
...
3 Deprecated Features
By deprecating a feature, the standards committee expresses the wish that the feature will go away
(§iso
...
However, the committee does not have a mandate to immediately remove a heavily used
feature – however redundant or dangerous it may be
...
It may disappear in the future
...

• Generation of the copy constructor and the copy assignment is deprecated for a class with a
destructor
...
3
...

• C++98 exception specifications are deprecated:
void f() throw(X,Y); // C++98; now deprecated

The support facilities for exception specifications, unexcepted_handler, set_unexpected(),
get_unexpected(), and unexpected(), are similarly deprecated
...
5
...
1)
...
Instead, use function and bind() (§33
...

• The auto_ptr is deprecated
...
2
...
3
...

In addition, the committee did remove the essentially unused export feature, because it was complex and not shipped by the major vendors
...
2
...
5
...

Programmers should seriously consider banning C-style casts from their own programs
...
The named casts should be preferred because they are more
explicit and more visible
...
2
...
4)
...
The fundamental aim of the standards effort was to ensure that implementers and users would have a single definition of C++ to
work from
...

Unfortunately, it is not uncommon for people to take their first serious look at C++ using a fiveyear-old implementation
...
Given a choice, no self-respecting professional would touch such an antique
...
For a novice, older implementations come
with serious hidden costs
...
Using a featurepoor older implementation, especially if guided by an antique tutorial, warps the novice’s programming style and gives a biased view of what C++ is
...
3)
...

There are still places, where for political reasons or lack of suitable tool chains, C is preferred
over C++
...
That way, you gain some
type safety, increase portability, and will be ready when C++ features become available to you
...
3
...

Use an implementation that conforms to the standard wherever possible, and minimize the
reliance on implementation-defined and undefined aspects of the language
...
This leads to better organized
and more maintainable programs than designing for a lowest-common-denominator subset of C++
...
See also §1
...
2
...
3 C/C++ Compatibility
With minor exceptions, C++ is a superset of C (meaning C11, defined by ISO/IEC 9899:2011(E))
...
Well-written C programs
tend to be C++ programs as well
...

The C99/C++11 incompatibilities are listed in §iso
...
At the time of writing, C11 is still very new
and most C code is Classic C or C99
...
3
...
Over the years, these languages have
evolved at different paces and in different directions
...
The resulting incompatibilities can make life miserable for people who use both C and C++, for people who write in
one language using libraries implemented in the other, and for implementers of libraries and tools
for C and C++
...
However, look at a
simplified family tree:
1967

Simula

BCPL
B
K&R C

1978

Classic C
1980

C with Classes

1985

Early C++

1989

ARM C++

1998

C++98

C99

2011

C++11

C11

C89

A solid line means a massive inheritance of features, a dashed line a borrowing of major features,
and a dotted line a borrowing of minor features
...
Each carries with it the key aspects of Classic C, and
neither is 100% compatible with Classic C
...
It is K&R C plus enumerations and struct assignment
...
Consider a simple Venn diagram:

Section 44
...
1

C and C++ Are Siblings

1273

C89

C++98

C++11

C99

C11

The areas are not to scale
...
C++11 has
most of C11 as a subset
...
For example:
C89 only
C99 only
C++ only
C89 and C99
C89 and C++
C++ and C99
C89, C++, and C99
C++11 only
C11 only
C++11 and C11

Call of undeclared function
Variable-length arrays (VLAs)
Templates
Algol-style function definitions
Use of the C99 keyword restrict as an identifier
// comments
structs
Move semantics (using rvalue references; &&)
Type-generic expressions using the _Generic keyword
Atomics

Note that differences between C and C++ are not necessarily the result of changes to C made in
C++
...
Examples are the ability to assign a T∗ to a void∗ and the linkage
of global consts [Stroustrup,2002]
...


44
...
2 ‘‘Silent’’ Differences
With a few exceptions, programs that are both C++ and C have the same meaning in both languages
...
In C++,
sizeof('a') equals sizeof(char)
...
4
...

• In C++, the name of a struct is entered into the scope in which it is declared; in C, it is not
...
For example:

1274

Compatibility

Chapter 44

int x[99];
void f()
{
struct x { int a; };
sizeof(x);
sizeof(struct x);
}

/* size of the array in C, size of the struct in C++ */
/* size of the struct */

44
...
3 C Code That Is Not C++
The C/C++ incompatibilities that cause most real problems are not subtle
...
This section gives examples of C code that is not C++
...
A comprehensive list of incompatibilities can be found in §iso
...

• In C, most functions can be called without a previous declaration
...
Where that sensible advice is followed, and especially where C compilers
provide options to enforce it, C code conforms to the C++ rule
...
For example, the previous
main() contains at least two errors as a C program
...

void f();
void g()
{
f(2);
}



/* call undeclared function */
/* call undeclared function */

/* argument types not mentioned */

/* poor style in C; not C++ */

Such use is deemed obsolete in ISO C
...
*/ }

/* C; not C++ */

Such definitions must be rewritten:
void f(int a, char∗ p, char c) { /*
...
For example:

Section 44
...
3

C Code That Is Not C++

struct S { int x,y; } f();
void g(struct S { int x,y; } y);



/* C; not C++ */
/* C; not C++ */

The C++ rules for defining types make such declarations useless, and they are not allowed
...
If one of these appears as an identifier in a
C program, that program must be modified to make it a C++ program:
C++ Keywords That Are Not C Keywords
alignas
bitor
compl
explicit
new
or_eq
static_cast
try
xor



alignof
bool
const_cast
false
noexcept
private
template
typeid
xor_eq

and
catch
constexpr
friend
not
protected
this
typename

and_eq
char16_t
decltype
inline
not_eq
public
thread_local
using

asm
char32_t
delete
mutable
nullptr
reinterpret_cast
throw
virtual

bitand
class
dynamic_cast
namespace
operator
static_assert
true
wchar_t

In addition, the word export is reserved for future use
...

In C, some of the C++ keywords are macros defined in standard headers:
C++ Keywords That Are C Macros
and
or



and_eq
or_eq

bitand
true

bitor
wchar_t

bool
xor

compl
xor_eq

false

not

not_eq

This implies that in C they can be tested using #ifdef, redefined, etc
...
As long as at most one such declaration provides an initializer,
the object is considered defined only once
...
2
...

In C, a void∗ may be used as the right-hand operand of an assignment to or initialization of a
variable of any pointer type; in C++ it may not (§7
...
1)
...
Note that the implicit
conversion of a void∗ to a different pointer type is not in general harmless:

1276

Compatibility

char ch;
void∗ pv = &ch;
int∗ pi = pv;
∗pi = 666;



Chapter 44

// not C++
// overwrite ch and other bytes near ch

If you use both languages, cast the result of malloc() to the right type
...

In C, the type of a string literal is ‘‘array of char,’’ but in C++ it is ‘‘array of const char,’’ so:
char∗ p = "a string literal is not mutable";
p[7] = 'd';



// error in C++; OK in C

C allows transfer of control to a labeled statement (a
initialization; C++ does not
...
6) to bypass an

goto foo;
// OK in C; not C++
//
...
*/
}



In C, a global const by default has external linkage; in C++ it does not and must be initialized, unless explicitly declared extern (§7
...
For example:
const int ci;



// OK in C; const not initialized error in C++

In C, names of nested structures are placed in the same scope as the structure in which they
are nested
...
*/ } t;
//
...
For example:
struct X { /*
...
For example:
char v[5] = "Oscar";
printf("%s",v);

// OK in C, the terminating 0 is not used; not C++
// likely disaster

Section 44
...
3
...
3
...
1 ‘‘Classic C’’ Problems
Should you need to upgrade Classic C programs (‘‘K&R C’’) or C89 programs, a few more problems will emerge:
• C89 does not have the // comments (though most C89 compilers added them):
int x;



// not C89

In C89, the type specifier defaults to int (known as ‘‘implicit int’’)
...
*/

}

44
...
3
...
3) that came from C++
...
3
...
The features are sorted by
purpose
...

• Features primarily for notational convenience:
[1] // comments (§2
...
1, §9
...
2
...
2
...
4
...
2
...
4
...
3); added to C99
[7] Declarations in for-statement initializers (§9
...
4
...
2
...
3
...
1); partially added to C (§44
...
3)
[2] Type-safe linkage (§15
...
2
...
2)

1278

Compatibility

Chapter 44

[4] const (§7
...
5); partially added to C
[5] The Boolean type bool (§6
...
2); partially added to C99
[6] Named casts (§11
...
2)
• Facilities for user-defined types:
[1] Classes (Chapter 16)
[2] Member functions (§16
...
1) and member classes (§16
...
13)
[3] Constructors and destructors (§16
...
5, Chapter 17)
[4] Derived classes (Chapter 20, Chapter 21)
[5] virtual functions and abstract classes (§20
...
2, §20
...
2
...
5)
[7] friends (§19
...
6)
[9] static members (§16
...
12)
[10] mutable members (§16
...
9
...
7)
• Features primarily for program organization (in addition to classes):
[1] Templates (Chapter 23)
[2] Inline functions (§12
...
3); added to C99
[3] Default arguments (§12
...
5)
[4] Function overloading (§12
...
3
...
3
...
4
...
1, Chapter 13)
[8] Run-Time Type Identification (Chapter 22)
[9] Generalized constant expressions (constexpr; §2
...
3, §10
...
1
...
2 are not in C
...
3
...
However, some facilities, such as function overloading and consts in constant expressions, are not identified by a keyword
...
This implies that on some (most?) implementations, a C++ function must be
declared extern "C" to be compiled as C++ and also conform to C calling conventions (§15
...
5)
...
2
...

In addition to the features listed, the C++ library (§30
...
1, §30
...
The
C standard library offers type-generic macros in ...
h>, approximating
...
h>, offering _Bool and the alias bool to approximate C++’s bool
...
4

Advice

1279

44
...
1
...
2
...

The common subset of C and C++ is not the best initial subset of C++ to learn; §1
...
3,
§44
...
4
...
1, §44
...
4
...
2
...
5
...
3
...
2
...
5
...
; §44
...
3
...
3
...

When converting a C program to C++, rename variables that are C++ keywords; §44
...
3
...
2
...

When converting a C program to C++, cast the result of malloc() to the proper type or change
all uses of malloc() to uses of new; §44
...
3
...
4
...
5
...
3
...
4
...
g
...
2
...
h> holds the C-style string functions); §15
...
4
...
h> that places names in the global namespace, the header
places the names in namespace std; §15
...
2
...
2
...


This page intentionally left blank

I
Index
Knowledge is of two kinds
...

– Samuel Johnson

time_point
1014
tuple
985
unique_ptr
987
valarray
1170

Token

""

!
logical not operator
logical_not 966
not
258
valarray
1170

empty string
177
operator
558

274

!=
bitset
980
container
902
duration
1012
error_categor y
877
error_code
875
iterator
959
match_results
1060
not-equal operator
41
not_eq 258
not_equal_to 966
pair
984
regex_iterator
1067
regex_token_iterator 1068
rel_ops 1029
shared_ptr
992
string
1040
sub_match
1058

"
double quote
176
prefix
147
string literal
39, 176
##
338
#
338
,
and []
183
no order
531
operator
260
predefined
531
prohibiting
531
$
character
155
regex
1052
$$ the $ character
1061
$& match
1061
$’ suffix
1061
$‘ prefix
1061
$1 first submatch
1061
%

1282

Index

duration
1012
format character
1255
modulus 966
modulus operator
40
remainder operator
40
valarray
1170
%=
duration
operator
valarray

1011
42
1167

&
address-of operator
45, 172
and 258
bitset
979
bitwise and operator
274
predefined
531
prohibiting
531
reference to
45, 190
valarray
1170
&&
bitand 258
logical and operator
260, 274
logical_and 966
no order
531
rvalue reference
75, 194
valarray
1170
&=
and_eq 258
atomic
1203
bitset
979
valarray
1167

character literal
143
prefix
147
single quote
143
(, regex 1052
()
and initializer
162
argument list
307
call operator
80, 550
function call
315
initialization problem
492
Matrix
833, 846
packaged_task 1238
vs
...

floating-point
146
infix
147
member access
48
member access operator
202
operator
466
regex
1052

...

class
812
ellipsis
321
exception
369
typename 812
/
divide operator
40
divides 966
duration
1012
valarray
1170
/∗ comment
239, 338
// comment
39, 238
/=
duration
1011
scaling operator
42
valarray
1167
:

::
and vir tual function, operator
589
namespace and
392
operator
466, 582
scope resolution operator
158, 468
using
403
::∗, pointer to member
607
;, semicolon
153, 202, 226
<<=
bitset
979
valarray
1167
<<
bitset
979
error_code
875
example, Season
1121, 1152
exception and
1132
money_put and
1138
num_put and
1131
output operator
39
output ostream
91
resolution
533
shared_ptr
992
string
1042
tuple
817
valarray
1170
<=
container
902
duration
1012
less-than-or-equal operator
41
less_equal
966
pair
984
rel_ops
1029
shared_ptr
992
string
1040
sub_match
1058
time_point
1014
tuple
985
unique_ptr
987
valarray
1170
<
comparison
891
container
902
duration
1012
error_categor y
877
error_code
875
iterator
959
less
966
less-than operator
41

1283

1284

Index

I

pair
984
shared_ptr
992
string
1040
sub_match 1058
time_point 1014
tuple 985
unique_ptr 987
valarray
1170

equivalence = and
510
error_categor y
877
error_code
875
iterator
959
match_results
1060
pair
984
pointer
177
regex_iterator
1067
regex_token_iterator
1068
shared_ptr
992
string
1040
sub_match
1058
time_point
1014
tuple
985
unique_ptr
987
valarray
1170

<>
specialization
682
template
731, 737
=
0
65, 598
and ==
41
and ==, equivalence
510
atomic
1200
auto
42
container
896
default
518, 524
delete 524
delete vs
...

160
initialization, Matrix
843
initializer
41, 175, 202
list
162, 286
list argument
319
Matrix
832
qualified
287
type of
289
unqualified
288
use of
159

?
:, arithmetic-if
regex
1052

275

?:
conditional expression
264, 275
operator
275
[, regex
1052
[&], lambda
294
[=], lambda
294
[]
, and
183
−> and ∗ and
553
array
976
array of
44
bitset
979
container
900
design of
562
iterator
lambda
294
map 910
match_results 1060
Matrix
833
string 1041
subscript operator
50
subscript operator
174
valarray
1168
\", double quote
143
\
backslash
39, 143
escape character
143
string literal
177
\’, single quote
143
−> and ∗ and []
553
], regex 1052
ˆ
bit_xor
966
bitset
979
bitwise exclusive or operator
274
regex
1052
valarray
1170
xor
258
ˆ=
atomic
1203
bitset 979
valarray
1167
xor_eq 258
_
and suffix
823
underscore character
155
_1, placeholders 967
_2, placeholders 967
{, regex 1052
{}
ambiguity
286

|
bit_or
966
bitset
979
bitwise or operator
or
258
regex
1052
valarray
1170

274

|=
atomic
1203
bitset
979
or_eq
258
valarray
1167
||
bitor
258
logical or operator
260, 274
logical_or
966
no order
531
valarray
1170
}, regex
1052
˜
bitset
979
bitwise complement operator
274
compl
258
destructor
63, 485
valarray
1170
0
=
65, 598
constant-expression
269
false and
139
null pointer
269
nullptr NULL
46
octal
145
octal digit
144
prefix
147
zero null
174
0X
hexadecimal
145
hexadecimal digit
144
0x prefix
147
1, true and
139

1285

1286

Index

A
\a, alert
143
a, file mode
1254
%a format
1256
%A format
1256
ABA problem
1202
ABI and layout
211
abor t()
372, 443
abs() 1163–1164
865
valarray
1170
absence of initializer
161
abstract
base class 598
class
598
class 65
class and design
617
class constructor
598
class destructor
598
class, use of
622
type
65
abstraction
data
11
elegant and efficient 9
mechanisms
5
access
571

...

976
assignment
180
associative
550
by string, initialization of
176
deallocate
281
fixed-length
174
function argument
184
initializer
175
initializer, difference from C
1276
layout
183, 1172
multidimensional
1172, 1175
numeric
1166
of []
44
of array
183
of reference
190
passing multidimensional
185
pointer and
179, 318
T[n] built-in
887
unique_ptr 988
valarray and
1166
zero-terminated
175
array 208, 974
[] 976
contiguous
887
data()
976
fill()
974
initialize
975
operation
974
representation
890
size()
976
swap()
974
tuple_element 977
tuple_size 977
vs
...
vector
976
863
arrow operator
552

I

ASCII
137
character set
143
UTF-8 and
179
asin()
1163
valarray
1170
assembler
14, 23
Asser t example
361
asser t()
360

873
NDBUG 873
Asser t::dynamic()
361
...
vir tual
636
type
153
Bases
...
technique
17
type
47, 139
type, constructor for
301, 494
type, move of
516
type, user-defined operator and
532
by value, return
517
_byname facet
1124
byte
150

C
C

23
and C++
9, 19
and C++ compatibility
1271
and C++ global locale 1154
and C++, learning
18
and exception
350
argument type, difference from
1274
array initializer, difference from
1276
compatibility
14
concepts in
708
const linkage, difference from
1276
declaration and definition, difference from
difference from
1271
enum, difference from
1275
function and exception
352

1275

1291

function call, difference from
1274
function definition, difference from
1274
headers
416
initialization and goto, difference from
1276
int implicit, difference from
1277
jump past initialization, difference from
1276
linkage to
428
locale
1114
macro, difference from
1275
programmer
19
sizeof, difference from
1273
struct name, difference from
1276
struct scope, difference from
1273, 1276
void ∗ assignment, difference from
1275
with Classes
22
with Classes language features
23
with Classes standard library
25
C# programmer
20

...
C file
425
%c format
1256
C++
and embedded systems
31
and infrastructure
10, 30
and libraries
31
and operating systems
30
and science
31
and Web
30
ANSI
25
C and
9, 19
compatibility, C and
1271
design aims
12
design of
9
earliest
12
feature summary
1277
general-purpose language
9
history
21
ideals
9
ISO
25, 135
large program and
16
learning
17, 1271
learning C and
18
meaning
23
programmer
19
pronunciation
23
pure
8
standardization
25
teaching and
17
timeline
22
tour of
37
use of
9, 30
C++-style thread support, C-style vs
...
)
98
category, facet
1124–1125
categor y, facet
1113
cauchy_distribution
1188
cbegin()
iterator
899
match_results
1060
string
1044
unordered_map
920

...

812
abstract
65
abstract base
598
and concept
449
and struct
454
base and derived
66
concrete
470, 478
declaration
454
definition
454
facet
1118
final
592
hierarchy 68
interface
48
invariant
454
lambda and local
291
locale
1112
member
48
nested
469
recursion
794
string
561
struct and
206, 454
typename and
668
union and
215

1293

1294

Index

user-defined type
450
vs
...
run-time
790
compl, ˜
258
complement operator ˜, bitwise
complete
encapsulation
482
specialization
731
complex 61, 129, 535
_Complex
1278
complex example
542

128–129, 865
complexity
algorithm
931
amortized
895
asymptotic
895
function and code
306
guarantee
894
operation
894
composite operator
536
composition
namespace 407, 409
of code, flexible
741
compositor
855
compound statement
227
computation
compile-time
124, 781
conditional
339
numerical
128
concept
704
ad hoc
708
and class
577
and predicate
672
and requirement
672
checking
709
class and
449
constraint
708
constraints check
715
discovering a
704
locale 1109
multi-argument
714
Range 929
semantics and
709
value
715
concepts
708
Enable_if and
799
history
29
in C
708
static_asser t and
709
concrete
class 470, 478
class
60
type
60, 470
type, reuse of
478
concurrency
114, 1191, 1209
bit fields and
1194

Index

274

initialization and
443
task-based
1235
condition
226
declaration in
232
pointer as
228
variable, mutex and
1219
conditional
computation
339
definition
795–796
evaluation
313
expression, ?:
264, 275
Conditional if
790
conditional
1025
condition_variable
119
constructor
1231
destructor
1231
native_handle()
1231
native_handle_type
1231
notify_all()
1231
notify_one()
1231
throws system_error
868
wait()
1231
wait_for()
1231
wait_until()
1231

119, 865
condition_variable_any
1235
consistency, sequential
1196
consistent specialization
735
∗const
154, 187
const
186
and linkage
422
constexpr
262
C-style string and
176
function
307
function argument
307
immutability
42
in constant expression
264
linkage, difference from C
1276
member
506
member function
461
physical and logical 462
pointer
187
pointer to
187
reference
190
Tuple example
807
variable
461
constant
186
enumerator as in-class
506
expression
43, 262
expression, address
267
expression, const in
264
in-class definition of
506
member
506
symbolic
264
time
894
constant-expression 0
269

1295

1296

Index

const_cast
298, 302
constexpr
and reference
312
const
262
function
43, 264, 307, 311
function arguments
266
immutability
42
type function
786
const_iterator
106, 896
const_local_iterator 896
const_pointer 896
const_pointer_cast(), shared_ptr
992
constraint
708
concept
708
constraints
check
709
check concept
715
const_reference const_value_type& 896
const_reverse_iterator
896
construct()
allocator 997
allocator_traits
998
construction
{}
299
bottom-up
486
explicit
487
order
487
partial
357
constructor
49, 455, 484
abstract class
598
allocator 997
and copy, default
509
and destructor
24, 483, 485, 500, 582
and template, copy
679
and type conversion
538, 543
and vir tual base
634
atomic
1200
bitset
978
call of
487
condition_variable 1231
container
896
copy
73, 482, 508
default
61, 493
delegating 502–503
destructor, RAII
486
disambiguation, {}-list
496
duration 1010
exception and
356–357
explicit 457, 499
for built-in type
301, 494
for class member
500
forwarding
503
future
1241
inheriting
594
initialization without
489
initialize by
492

I

initializer-list
64, 495
invariant and
56
{}-list
495
locale
1116
map
910
match_results
1060
move 75, 482, 515
mutex
1221
packaged_task
1238
pair
983
POD and
212
pointer to
597
promise
1237
protected
1119
regex_iterator
1067
regex_token_iterator
1068
return type
484
shared_ptr
992
simplifies implementation
473
string
1039
thread
1210, 1212
timed_mutex
1224
time_point
1013
tuple
984
unique_lock
1227
unique_ptr
987
unordered_map
915
vir tual
597, 623
weak_ptr
994
constructors, initialization using
491
const_value_type&, const_reference
consume operation
1199
container
62, 78, 95
!= 902
<= 902
< 902
== 902
= 896
>= 902
> 902
[]
900
adaptor
887
adaptors
920
adding to
963
algorithm
103, 109, 411, 928
almost
973
assign()
896
associative
886, 909
at()
900
back()
900
capacity()
898
clear()
898, 901
comparison
902
constructor
896
destructor
896
emplace()
901

896

–C–

emplace_back() 900
empty()
898
erase()
901
front()
900
hash
887
implementation of
888
inser t()
901
iterator algorithm
953
maxsize()
898
member types
896
object in
97
operation
893
operation overview
893
ordered
909
ordered associative
909
overview
101, 885
pop_back() 900
push_back() 900
representation of
888
reser ve()
898
resize()
898
return
104
sequence
886
shrinktofit()
898
size()
898
sor t()
124
standard library
101
subscripting
900
swap()
902
unordered
909
unordered associative
887, 913
containers
almost
887
list of
863
contents-of operator ∗
45
context
of template definition
746
of template instantiation
746
contextual
keyword final 593
keyword override
590
contiguous
array
887
vector
886
contiguously, basic_string 887
continue 237, 252
statement
252
contravariance
610
control
override
589
structure, compile-time
789
controlled statement
233
convenience
and orthogonality
862
vs
...
cpp file
425
crbegin()
iterator
899
string 1044
creation, localization of object
623
cref() 968
cregex_iterator 1067
cregex_token_iterator 1068
crend()
iterator
899
string 1044
criteria, standard library
861
critique, design
616, 622
Crowl, Lawrence
1200

865, 1264
cshift()
1169
865
866

865

I


866

150

865

416, 428, 864
444, 863–865, 1164
abs()
865
div()
865
c_str(), string
1041

864
C-style
cast
302
cast, deprecated
1271
error handling
1163
string
46, 175
string and const
176
string, hash of
915
vs
...
h>
864

864
cultural preference, locale
1109
curbing code bloat
732
currency
symbol, international
1136
symbol, local
1136
symbol, standard
1136
current_exception()
374, 870
curr_symbol(), moneypunct
1136
Currying
967
customization point
737
cv_status::notimeout
1231
cv_status::timeout
1231
Cvt_to_upper example
1148
864, 1124

864

...
count(), duration
1010
D&E 10, 22
deadlock
118
mutex and
1223
deallocate array
281
deallocate()
allocator 997
allocator_traits
998
deallocation
63
allocation and
277, 556
debugging
454
deca 1018
decay
1023
deci 1018
decimal
145
decimal_point() 1129
moneypunct 1136
declaration
40, 151, 153
and definition, difference from C
1275
and definition, namespace member
400
class
454
enum class
221
function
305, 307
in case
232
in condition
232
in for statement
235
interface
51
on branch
229
point of
158
statement
227
struct name
205
using 393
declarations, keeping consistent
424
declarator operator
46, 154
decltype 165
auto
163
declval 1027
decrement
increment and
554
operator -42, 276
deducing template argument
685, 687
deduction

Index

reference
688
rvalue-reference
688
deep copy
511
default
argument
324
argument value, example of
457
comparison
891
constructor
61, 493
constructor and copy
509
initialization
161
initialization union
216
initializer
159
member initialization
501
memberwise
519
operation, choosing
523
operation, generate
517
operation, invariant and
520
operations, using
520
operator, meaning of
519
template argument
728
underlying type
219, 223
value
473, 490
value, choice of
495
default
231, 244
=
518, 524
default_error_condition()
error_categor y
877
error_code
875
default_random_engine
1183
defer_lock_t
1227, 1229
#define
336
defining a template
669
definition
152
check, template
717
class
454
conditional
795–796
context of template
746
difference from C declaration and
1275
function
307
implementation
51
in-class
460
namespace member declaration and
400
of constant, in-class
506
of vir tual function
586
point of
204, 748
using directive and
408
degrees of exception safety
375
delayed
checking, ::type
784
type checking
784
Delayed
785
delays, shared_ptr
991
delegating constructor 502–503
delegation 554
delete element from sequence
938
delete

1299

1300

Index

=
524
a function
524
an operation
77
and operator delete()
556
conversion
524
destructor and
488
double
279
free-store allocation
525
naked
64
nothrow 285
nullptr
279
operator
63, 277
placement
283
premature
279
stack allocation
525
vs
...
count()
1010
duration_cast()
1012
hours
1012
max()
1012
microseconds
1012
milliseconds
1012
min()
1012
minutes
1012
nanoseconds
1012
seconds
1012
time_point
1013
zero()
1012
duration_cast
123
duration_cast(), duration
1012
dynamic
memory
277
store
63
dynamic_cast
298
throws bad_cast
868
dynamic_pointer_cast(), shared_ptr

992

1301

1302

Index

E
E infix
147
e, floating-point
146
%e format
1256
e infix
147
earliest C++
12
ec
...

321
elliptic
1164
else
228
embedded systems, C++ and
31
emphasis, examples and
7
emplace()
container
901
map
910
emplace_after(), forward_list 908
emplace_back(), container
900
emplace_front(), list
907
emplace_hint(), map
910
Employee example
578
empty
base optimization
804
sequence
954
statement
226
string ""
177
empty()
container
898
match_results 1060
string
1040
Enable_if
and concepts
799
and overloading
801
implementation of
799
enable_if 795, 1025
notation
797
use
797
encapsulation, complete
482
encoding(), codecvt
1148
end() 99, 103, 954
iterator
899
match_results 1060

I

nonmember
964
string
1044
unordered_map
920
valarray
1170
#endif
339
enforcing invariant
359
engine, random
129
entanglement
511
and garbage collection 512
enum
201, 218
and enum class
218
and integer
223
bitset and
977
class
201
class and integer
221
class conversion, undefined
221
class declaration
221
class, enum and
218
class enumeration
50, 219
class, sizeof
222
class underlying type
219
conversion, undefined
223
difference from C
1275
enumeration
50
member
506
plain
222
range of
223
sizeof
223
switch and
231
underlying type
223
unnamed
224
user-defined operator
220
user-defined operator and
532
user-defined type
220
enumeration
218
enum
50
enum class
50, 219
switch on
219
enumerator
218
as in-class constant
506
scope
218
environment, floating-point
866
eof(), char_traits
1035
epsilon()
1161
eq(), char_traits
1035
eq_int_type(), char_traits
1035
equal operator == 41
equal()
934
equality without == 892
Equality_comparable
714, 716
equal_range()
126, 945
equal_to
887
==
966
equation, Matrix linear
849
equivalence
= and == 510

–E–

type
210, 673
equivalent() error_category
877
ERANGE
1163
erase()
99
container
901
string
1044
erase_after(), forward_list
908
erasure, type
733
errc
POSIX
880
systemcategor y()
880
errno 350, 1163
...
categor y()
875
hash of
915
mapping
879
message()
875
=n()
875
to bool 875

Index

value()
875
error_condition
878
error-handler function
346
escape character \
143
essential operations
482, 517, 561
Estd sort()
411
evaluation
compile-time
43
conditional
313
order of
259
partial
967
short-circuit
229, 260
event, asynchronous
348
exa
1018
example
anonymous union
564
Asser t
361
Assoc
550
Bases
...

369
and <<
1132
and constructor
356–357
and destructor
356
and error
345, 348
and main()
98
and member
357
and member initialization
371
and new 357
and old code
349
and recursive function
348
and subobject
357
and thread
374
and time critical
349
assignment and
381
atexit() and
352
C and
350
C function and
352
can’t use
349
catch every
98
copy and
364
copy of
368
cost of
351
goto and
238
guarantee
353
packaged_task and
1238
propagation 870
qsor t() and
352
runtime_error
1116
safe
353
safety, degrees of
375
safety, techniques for
375

I

specification
26, 367
specification, deprecated
1270
standard library
868
transparency
378
uncaught
372
exception hierarchy 870

372, 864–865
exception_ptr
870
exceptions()
1132
exception-safe code
378
exchange(), atomic
1200
exclusive or operator ˆ, bitwise
274
exercises – see www
...
com
exhaustion, free store
283
exit
from function
310
loop
236
exit()
443
exp(), valarray
1170
expired(), weak_ptr
994
explicit
call of destructor
285
construction
487
conversion
457
destruction
487
qualification
588
specialization
693
template argument
686
template instantiation
744
type conversion
298
explicit
constructor
457, 499
conversion operator
545
exponent, size of
1161
exponential_distribution
129, 1187
exponentiation
∗∗
529
vector
1170
expor t
26, 156
removed
1270
Expr example
596
expr()
1163
expression
?: conditional
264, 275
address constant
267
const in constant
264
constant
43, 262
full
261
lambda
81, 290
statement and
225
extended integer
145
extended, regex
1057
extent
1022
extern
428
extern
421
external linkage
421

–E–

externally imposed layout
212
extreme_value_distribution 1187

F
F suffix
147
%F format
1256
%f format
1256
\f, formfeed
143
f suffix
147
fabs() 1163
facet
access to
1119
_byname 1124
category
1124–1125
categor y 1113
class 1118
codecvt
1146
collate 1126
ctype
1143
identifier id
1119
lifetime of
1119
locale and
1109, 1113
messages
1150
money_get 1138
moneypunct 1135
money_put 1137
numpunct
1129
num_put
1130
put() iterator
1130
Season_io, user-defined
1120
standard
1124
to locale, adding
1117
use of
1119
user-defined
1123
facilities
basic language
4
standard library
88, 860
use of C++11
8
factory
623
failed()
1132
failure
output
1132
precondition
359
false
and 0
139
false_type and
800
falsename()
1130
false_type and false
800
fault tolerance
350
feature
deprecated
1270
summary, C++
1277
vs
...
C
425

...
cc
425

...
cxx
425

...
hh
425
mode a
1254
mode b
1254
mode r
1254
mode w
1254
mode x
1254
source
419
__FILE__
340
File_ptr example
357
fill()
941
array
974
fill_n()
941
final
591
and performance
592
class
592
contextual keyword
593
function
307
finally()
358
find()
103, 933
char_traits
1035
example, parallel
1246
map
910
string
1046
find_all() example
104
find_end()
933
find_first_not_of(), string
1047
find_first_of()
933
string
1047
find_if()
108, 933
find_if_not()
933
find_last() example
962
find_last_not_of(), string
1047
find_last_of(), string
1047
firewall
350
first submatch, $1
1061
first, pair member
127, 983

1305

1306

Index

fisher_f_distribution 1188
fixed-length array
174
flags, match
1062
flags(), regex
1057
flexible composition of code
741
flip() bitset
979
float 146
bits in
1161
sizeof
150
float_denorm_style
1161
<float
...

146
conversion
269
conversion to
270
e
146
environment,
866
hash of
915
literal
146
promotion
267
to int
270
type
139, 146
float_round_style 1161
floor()
1163
FLT_RADIX 1162
fmod() 1163
fold()
701
for
and :
233
range
868
loop, lambda and
292
statement
45, 235
statement, declaration in
235
statement, range
45, 233, 965
for(;;) forever
235, 244
for_each()
932
forever, for(;;)
235, 244
formal argument
315
format
%A
1256
%a 1256
%c
1256
character %
1255
%d
1256
%e
1256
%F
1256
%f
1256
%G
1256
%g
1256
%i 1256
%n
1256
number
1129
%o
1256
of monetary amount
1134–1135
%p
1256
%s
1256

I

string
1255
substitution
1061
%u
1256
%X 1256
%x 1256
format()
options
1062
regex
1061
format_default ECMAScript rules
format_first_only
1062
format_no_copy
1062
format_sed
1062
formfeed \f
143
Fortran
16
forward
iterator
955
reference to class
571
forward()
1028
forward_as_tuple(), tuple
985
forwarding constructor
503
Forward_iterator
716
forward_iterator_tag
956
forward_list
906
emplace_after()
908
erase_after()
908
inser t_after()
908
operation
893, 907–908
representation
889
singly-linked list
886
size()
907
splice_after()
908

863
frac_digits()
monetar y
1137
money_punct
1135
free
storage
167
store
63, 167, 277
store exhaustion
283
freestanding implementation
137
free-store allocation, delete
525
frexp()
1163
friend
571
and member
532, 574
class
572
function
572
lookup
573
template and
682
from_time_t(), clock
1015
front()
container
900
of queue
922
string
1041
front_inser ter()
963
front_inser t_iterator
963

864

1062

–F–

full expression
261
__FUNC__ 340
function
39
access
216
adaptor
967
and code complexity
306
and exception, C
352
argument
315
argument, array
184
argument const
307
argument names
308
argument passing
315, 482
argument type check
315
argument type conversion
315
argument types, vir tual
586
argument unused
308
arguments, constexpr
266
body
39, 307
body, tr y block as
98, 371
call
315
call ()
315
call and assignment
192
call, difference from C
1274
const
307
const member
461
constexpr
43, 264, 307, 311
constexpr type
786
declaration
305, 307
definition
307
definition, difference from C
1274
definition of vir tual 586
definition, old-style
1274
delete a
524
error-handler
346
exit from
310
final 307
friend 572
get
541
helper
542
implementation of vir tual
67
init()
455
inline 307, 310
inline member
460
long
306
mathematical
128
mathematical special
1164
member
451, 473
name, overloaded
326
noexcept
307, 365
[[noreturn]]
307, 314
object
80, 551
object, lambda and
291
only, instantiate used
743
operator :: and vir tual
589
override
307
parameter
315

Index

parameter pack
812
pointer to
332
pointer to member
607
pure vir tual
598
requirement, class vs
...
h file
424
half-open range
954
handle
49, 64, 280
resource
73, 113
handle_ioexception()
1132
handler, unexpected
367
hardware
149
dependency
136
hardware_concurrency(), thread
has identity
166, 171
has_denorm
1161

1210

–H–

has_denorm_loss 1161
Has_f example
799
has_facet()
1119
hash
container
887
policy
919
table
100, 887
hash 887
of bitset
915, 980
of bool 915
of C-style string
915
of error_code
915
of floating-point
915
of integer
915
of pointer
915
of shared_ptr
915
of string
915
of thread::id
915
of typeindex 915
of u16string 915
of unique_ptr 915
of wstring 915
specialization
915
user-defined
916
hash(), collate 1126
hashed
unordered_map 887
unordered_multimap 887
unordered_multiset
887
unordered_set
887
hasher 896
hash_function(), unordered_map
has_infinity 1161
has_quiet_NaN 1161
has_signaling_NaN 1161
has_vir tual_destructor
1022
header
253, 424
and compile time
435
file
52, 424
language support
866
single
431
standard library
89, 428, 863
headers
C
416
multiple
435
use of
439
heap
63
operation
948
store
277
heap, priority_queue and
924
heartbeat
1215
hecto 1018
Heisenbug
1216
Hello, World! example
39
helper
function
542

Index

function and namespace
475
Hermite polynomials
1164
hexadecimal
0X
145
digit 0X
144

...

859
HOPL
22
horizontal tab \t
143
hosted implementation
137
hours, duration
1012
Hume, David
134
hybrid language 12

I
919

%i format
1256
\i, regex
1055
$i submatch
1061
icase, regex
1057
id
facet identifier
1119
thread
1210–1211
ideal library
111
ideals
C++
9
design
10
programming
10
identifier
155
id, facet
1119
identity
has
166, 171
thread
1211
IEC-559, is_iec559
1161
IF, compile-time
794
if
compile-time
790
Conditional
790
statement
43, 228
_if suffix
930
if, switch and
230
#ifdef
339

1309

1310

Index

#ifndef 339, 441
$ii submatch
1061
imbue()
iostream locale 1111
regex
1057
regex_traits
1070
immutability
const
42
constexpr
42
immutable
461
locale is
1118
state
512
string literal
176
implementation
alternative
620, 734
and interface
616
classes, multiple
624
definition
51
dependency type of integer literal
146
freestanding
137
hosted
137
inheritance
70, 578, 599, 637
interface and
419, 450, 599, 636
iterator
105
lambda
290
Matrix
840
namespace, interface
404
of container
888
of Enable_if 799
of vir tual function
67
pre-standard
1271
priority_queue 923
shared
624
specialization
734
stack
920, 922
implementation-defined
135
_impl
...

147
e
147
E
147
infrastructure, C++ and
10, 30
inheritance
66, 579, 583
access control and multiple
606
ambiguity resolution, multiple
627
implementation
70, 578, 599, 637
interface
70, 578, 599, 617, 637
multiple
24, 583, 624
repeated
630
template and
673
inheriting constructor
594
init() function
455
initialization
153, 455
{} 456, 489, 492
() vs
...

963
inser t_iterator
963
instantiate used function only
743
instantiation
context of template
746
directive, template
744
explicit template
744
member
744
multiple
744
multiple point of
752
needed
743
point of
749
template
671, 742
instruction reordering
1195
int
40, 144, 150
and pointer
150
bits in
1161
floating-point to
270
implicit, difference from C
1277
largest
1161
output bits of
981
sizeof
150
smallest
1161
template argument
685
int32t
168
integer
conversion
268
conversion, signed unsigned
268
enum and
223
enum class and
221
extended
145
hash of
915
literal
145, 218
literal, implementation dependency type of
literal, type of
146
type
139, 144
type, conversion to
270
value character
141
integral
conversion to
270
promotion
267
type
139
interface
and implementation
419, 450, 599, 636
class
48
declaration
51
implementation and
616
implementation namespace
404
inheritance
70, 578, 599, 617, 637
module and
399
multiple
624
shared
624

1311

146

1312

Index

specialization
733
internal linkage
421
international currency symbol
1136
internationalization, approaches to
1110
interoperability
16
INT_MAX 1162
introducer, lambda
293
int_type(), char_traits
1035
invalid_argument, bitset throws
868
invalidate iterator
898
invariant
56
and constructor
56
and default operation
520
class
484
class 454
enforcing
359
implicit
520
partially specified
522
rationale
485
resource
521
I/O 91
example, String 568
iterator and
106
I/O, string 1042
io_errc iostream_category() 883
864

864
ios_base::failure, iostream throws
868

864
iostream
91
locale and
1114, 1123
locale, imbue()
1111
throws ios_base::failure 868

39, 864
iostream_categor y()
877
io_errc
883
is(), ctype 1143
is_abstract
1020
isalnum()
1034
locale 1154
isalpha()
249, 1034
locale 1154
is_arithmetic
1019
is_array
1018
is_assignable 1020
is_base_of 1022
isblank() locale 1154
is_bounded 1161
is_class
1018
iscntrl()
1034
locale 1154
is_compound 1019
is_const
1020
is_constructible 1020
is_convertible 1022
is_copy_assignable 1020

I

is_copy_constructible
1020
isctype(), regex_traits
1070
is_default_constructible
1020
is_destructible
isdigit()
1034
locale
1154
is_empty
1020
is_enum
1018
is_exact
1161
is_floating_point
1018
is_function
1018
is_fundamental
1019
isgraph()
1034
locale
1154
is_heap()
948
is_heap_until()
948
is_iec559 IEC-559
1161
is_integer
1161
is_integral
1018
is_literal_type
1020
is_lock_free(), atomic
1200
islower()
1034
locale
1154
is_lvalue_reference
1018
is_member_functionpointer
1018
is_member_objectpointer
1018
is_member pointer
1019
is_modulo
1161
is_move_assignable
1020
is_move_constructible
1020
is_nothrow_assignable
1022
is_nothrow_constructible
1022
is_nothrow_copy_assignable
1022
is_nothrow_copy_constructible
1022
is_nothrow_default_constructible
1022
is_nothrow_destructible
1022
is_nothrow_move_assignable
1022
is_nothrow_move_constructible
1022
ISO
C++
25, 135
core language
38
standard
135
standard library
38
ISO-14882
25
ISO-4217
1136
ISO-646
137
is_object
1019
is_par titioned()
940
is_permutation()
940
is_pod
1020
is_pointer
1018
is_polymor phic
1020
isprint()
1034
locale
1154
ispunct()
1034
locale
1154

–I–

is_reference
1019
is_rvalue_reference
1018
is_same
1022
is_scalar
1019
is_signed
1020, 1161
is_sor ted()
942
isspace locale 1154
isspace()
1034
whitespace
250
is_specialized 1161
is_standard_layout 1020
is_steady(), clock
1015
istream >>, input
93

864
istream_iterator
106
is_trivial 1020
is_trivially_assignable 1021
is_trivially_constructible 1021
is_trivially_copyable 1020
is_trivially_copy_assignable 1021
is_trivially_copy_constructible 1021
is_trivially_default_constructible 1021
is_trivially_destructible 1021
is_trivially_move_assignable 1021
is_trivially_move_constructible 1021
is_union 1018
is_unsigned 1020
isupper()
1034
locale
1154
is_void
1018
is_volatile
1020
isxdigit()
1034
locale
1154
iteration
compile-time
793
statement
233
iterator
103

959
+
-959
->
959
-=
!=
959
<
959
[]
==
959
959
+=
959
>=
959
++
959
>
959
adaptor
960
advance() 959
algorithm and
927
algorithm container
953
and I/O
106

Index

begin()
899
bidirectional
955
cbegin()
899
cend()
899
crbegin()
899
crend()
899
distance()
959
end()
899
facet put()
1130
forward
955
generality and
929
implementation
105
input
955
invalidate
898
move
964
next()
959
operation
959
output
955
prev()
959
random-access
955
rbegin()
899
rend()
899
STL
954
string
1044
valarray
1173
iterator
99, 106, 896, 958

125, 956
range for
868
iterator_categor y
125
iterator_traits
957
iterator_traits
124–125, 788, 956
difference_type
957
iterator_categor y
957
pointer
957
reference
957
value_type
957
iterator_type
125
iter_swap()
942
itoa()
322
Ival_box example
614
Ival_slider
636

J
Java programmer
20
JIS
1146
join()
115
thread
1210, 1214
thread destructor and
1215
joinable(), thread
1210
jump past initialization, difference from C

K
keeping consistent declarations

424

1276

1313

1314

Index

I

and library
87
C++ general-purpose
9
facilities, basic
4
features, C with Classes
23
features, C++11
28
features, C++98
26
high-level
15
hybrid 12
library system
15
low-level
15
people and machines
9
programming style
17
scripting
16
support
865–866
support header
866

key and value
100
key_comp(), map
910
key_compare
896
key_eq(), unordered_map 919
key_equal 896
key_type
896
keyword
156
final, contextual
593
override, contextual
590
kilo
1018
knuth_b
1184

L
L" prefix
147
L’ prefix
147
L suffix
147
L’, wide-character literal
144
\L, regex
1054
\l, regex
1054
l suffix
147
label
: 226
scope of
238
labs()
1164
lack
of initializer
490
of modularity
585
Laguerre polynomials
1164
lambda
[=]
294
[] 294
[&]
294
alternatives
291
and for loop
292
and function object
291
and global name
295
and local class
291
and member name
296
and namespace name
295
capture
293
capture list
293
closure
291
expression
81, 290
implementation
290
introducer
293
lifetime
295
mutable
296
named
297
operator()()
296
recursive
297
state
296
template argument
727
this
296
type of
297
language

large
character set
144
program
435, 437
program and C++
16
larger character set
178
largest int
1161
launch, async()
122
launch::async, async()
1245
launch::deferred, async()
1245
launcher, async() task
1245
layout
ABI and
211
array
183, 1172
class
579
externally imposed
212
object
151
struct
203
Tuple
804
type, standard
211
vir tual base
633
lazy
match
1053, 1056
match, (?
1056
ldexp()
1163
ldiv()
1164
ldiv_t
1164
leak, resource
76, 112
leaked object
279
learning
C++
17, 1271
C and C++
18
Legendre polynomials
1164
length
of name
155
valarray
1169
length()
char_traits
1035
codecvt
1148
match_results
1060
regex_traits
1070
string
1040

–L–

sub_match 1058
length_error, string throws
868
less
887
<
966
less_equal <= 966
less-than operator <
41
less-than-or-equal operator <=
41
letter, [[:alpha:]]
1054
lexical token
258
lexicographical order
949
lexicographical_compare()
949
libraries, C++ and
31
library
9
algorithm, standard
109
and error
344
C with Classes standard
25
C++11 standard
29
C++98 standard
26
container, standard
101
facilities, standard
88, 860
ideal
111
language and
87
non-standard
88
standard
6, 88, 111, 416
standard – see standard library
system, language
15
life cycle, object
481
lifetime
482
lambda
295
of facet
1119
of locale 1130
of object
166
of temporary
261
lifting and algorithm
701
limits, numeric
1160

124, 131, 865, 1160
...
h>
864
locale-sensitive message
1149
local_iterator
896
locality
437
localization of object creation
623
location, memory
1193
lock
1192
lock()
118, 1229
and RAII
118
mutex
1221
timed_mutex
1224

I

unique_lock
1227
weak_ptr
994
lockable object
1227
lock_guard and unique_lock
1225
lock_guard
1225
locking
357
double-checked
1203
locks, multiple
1228
log()
1163
valarray
1170
log10()
1163
valarray
1170
logarithmic time 894
logical
and operator && 260, 274
const, physical and 462
not operator !
274
operators, bitwise 274
or operator ||
260, 274
program structure
420
logical_and &&
966
logical_not !
966
logical_or ||
966
lognormal_distribution
1188
long
function
306
namespace name
406
long
144
double
146
double, sizeof
150
long long
144
long
long, sizeof
150
sizeof
150
longjmp()
865, 1264
lookup
argument-dependent
395, 754
base class
756
error, name
674
friend
573
namespace name
395, 533
lookup_classname(), regex_traits
1070
lookup_collatename(), regex_traits
1070
loop
233
body
233
exit
236
lambda and for 292
merging
853
statement
252
lower, regex
1054
lower_bound()
945
map
910
low-level language
15
lt(), char_traits
1035
lvalue
165–166, 575
modifiable
165

–L–

reference

Index

190

M
m, _m vs
...
m
823
Machiavelli, Niccol`
o
448
machines, language people and
9
macro 336
alternative to
338
difference from C
1275
predefined
340
template and
750
magnitude ratio, SI
1018
main()
39, 252, 441, 443
and initialization
442
argument to
253
argv argc
253
exception and
98
maintenance
437
make_error_code()
875
make_exception_ptr() 870
make_heap() 948
make_move_iterator()
964
make_pair() 127
makepair(), pair
984
make_ready_at_exit(), packaged_task
makeshared(), shared_ptr
992
make_signed 1024
make_tuple 817
make_tuple() 127, 808
maketuple(), tuple
985
make_unsigned 1024
management, resource
13, 76, 112
manager object
280
mantissa, size of
1161
manual
overload resolution
330
tutorial and
3
map
100, 909
[]
910
at()
910
constructor
910
emplace()
910
emplace_hint() 910
find()
910
inser t()
910
key_comp()
910
lower_bound()
910
operation
893, 910
ordered
886
representation
889
subscripting
910
upper_bound() 910
value_comp()
910

1238


863
mapped type, value
100
mapped_type
896
mapping error_code
879
map-reduce
1249
Marian
153
markcount(), regex
1057
mask, character
1142
match
$&
1061
(? lazy
1056
flags
1062
greedy
1053, 1056
lazy
1053, 1056
match_any
1062
match_continuous
1062
matches and submatches
1060
match_flag_type, regex_constants
match_not_bol
1062
match_not_bow
1062
match_not_eol
1062
match_not_eow
1062
match_not_null
1062
match_prev_avail
1062
match_results
1059
!=
1060
[]
1060
== 1060
=
1060
begin()
1060
cbegin()
1060
cend()
1060
constructor
1060
destructor
1060
empty()
1060
end()
1060
get_allocator()
1060
length()
1060
maxsize()
1060
position()
1060
prefix()
1060
ready()
1060
size()
1060
str()
1060
subscript
1060
suffix()
1060
swap()
1060
mathematical
function
128
functions, standard
1163
functions, valarray
1170
functions, vector
1170
special function
1164
...
∗, pointer to
607
access
466
access
...

202

I

920

919

access operator ->
202
alias, template
676
and nonmember operators
535
assignment must be
531
class
48
class
469
class template
675
const
506
constant
506
constructor for class 500
destructor, base and
486
enum
506
exception and
357
friend and
532, 574
function
451, 473
function, const
461
function, inline
460
function, pointer to
607
function, static
467, 571
function, template
676
initialization, default
501
initialization, exception and
371
initialization, order of
501
initialization, reference
495
initialization, static
506
initializer
500–501
initializer, in-class
459
instantiation
744
name, lambda and
296
nullptr, pointer to
607
of base class, private
581
of derived class
581
operator delete()
557
operator() must be
531
operator-> must be
531
operator= must be
531
operator[] must be
531
operator new()
557
pointer to
607, 609
private class
453
protected
603–604
public class
453
static
467, 557
struct
202
template
670
template data
675
template static
676
template, template
678
type
469
type, template
677
typedef, template
676
types, container
896
union
215
using and
593
using, template
676
void ∗, pointer to
607

–M–

memberwise
copy
453, 482, 519
default
519
initialization
489
move
519
memcpy()
210
mem_fn()
969
mem_fun() deprecated
967
mem_fun_ref() deprecated
967
memory
access time
1195
buffer
1005
cache
1193
dynamic
277
location
1193
management, example of user-defined
model
1193
model, relaxed
1199
order
1195
representing
379
uninitialized
1005

112, 863, 1005
unique_ptr 987
memor y_order
1199
merge()
946
list
907
mersenne_twister_engine 1183
message
catalog
1149
locale-sensitive
1149
queue 922
message()
error_categor y
877
error_code
875
messages
close()
1150
facet 1150
get()
1150
open()
1150
messages_base 1149
metaprogramming
779
and programming
781
template
779
when to use
794
method
586
micro
1018
microseconds, duration
1012
milli
1018
milliseconds, duration
1012
min()
950, 1161
duration
1012
time_point 1014
valarray
1169
min_element()
950
min_exponent 1161
min_exponent10 1161

Index

561

minmax()
950
minmax_element()
950
minstd_rand
1184
minstd_rand0
1184
minus operator 40
minus 966
minutes, duration
1012
mismatch()
934
missing, = delete vs
...

609

...
, member access
202
-, minus
40
%, modulus
40
∗, multiply
40
!=, not-equal
41
<<, output
39
+, plus
40
%, remainder
40
∗=, scaling
42
/=, scaling
42
::, scope resolution
158, 468
[], subscript
174
++, user-defined
531, 554
->, user-defined
552
=, user-defined
575
+=, user-defined
531, 536, 575
+, user-defined
532, 575
--, user-defined
554
and built-in type, user-defined
532
and enum, user-defined
532
application
550
arithmetic
40
arrow
552
assignment
244, 536
associativity of
257
binding strength
257
comparison
41
composite
536
declarator
46, 154
delete
63, 277
design of access
562
enum user-defined
220
explicit conversion
545
literal
558
meaning of default
519
new
63, 277

1323

1324

Index

noexcept 366
overloaded
62, 477
overloading, example of
561
precedence
255
predefined meaning for
531
return from
532
special
549
summary
255
symmetric
539
template literal
560
type conversion
543
user-defined
62, 529
user-defined binary
530
user-defined unary
530
operator
""
558
[], subscript
50
delete()[]
282
delete()
282
delete and size
557
delete(), delete and
556
delete(), member
557
functions, list of
529
operator-> must be member
531
operator= must be member
531
operator
new()
282
new()[]
282
new and size
556
new(), member
557
new(), new and
556
operator=, vector
382
operator()
80, 550
operator()(), lambda
296
operator() must be member
531
operator[]
550
must be member
531
operators
and namespace 533
bitwise logical
274
member and nonmember
535
n-ary
853
optimization
853
empty base
804
short string
561, 563–564
optimize, regex
1057
options, format()
1062
or
|
258
operator |, bitwise
274
operator ||, logical
260, 274
order
891
bitset bit
978
collating
1128
construction
487
destruction
487

I

initialization
487
lexicographical
949
memory
1195
of evaluation
259
of member initialization
501
of specialization
736
strict weak
891
string
1128
total
892
vector bit
982
ordered
associative container
909
container
909
map
886
multimap
886
multiset
886
set
886
type
707
Ordered
707, 709, 716
or_eq, |= 258
organization
of book
4
standard library
863
orthogonality, convenience and
862
ostream <<, output
91

864
ostream_iterator
106
out(), codecvt
1148
out_of_range
97
bitset throws
868
string throws
868
vector throws
868
output
91
bits of int
981
bitset
979
cout
39
failure
1132
input and
864
iterator
955
of monetary amount
1137
of numeric value
1130
of user-defined type
94
operator << 39
ostream <<
91
sequence
955
string
93
Output_iterator
716
output_iterator_tag
956
overabstraction
10
overaggressive ADL
754
overflow, stack
922
overflow\rror, bitset throws
868
overload
new
283
resolution
327
resolution for multiple arguments

329

–O–

resolution, manual
330
return type and
328
scope and
328
overloaded
function name
326
operator
62, 477
overloading
and base
693
and derivation
693
bind() and
968
Enable_if and
801
example of operator
561
function template
689
namespace and
410
specialization and
737–738
override
66, 587, 598, 631
control
589
from vir tual base class
638
override
590
contextual keyword
590
function
307
overriding function, type of
596
overuse of traits
789
overview
container
101, 885
container operation
893
overwriting vs
...

607
to member ::∗
607
to member and offset
608
to member function
607
to member nullptr
607
to member void ∗
607
to void
173
valid
140, 228
value_type of
788
pointer
896
iterator_traits
957
pointers
and garbage collection 512
and ownership
188
pointer_traits
999
point-of-instantiation ambiguity
752
Poisson distributions
1187
poisson_distribution
1187
policy, hash
919
pollution, namespace
223
polymorphic type
66, 587
polymorphism
578
– see virtual function
runtime
587
polynomials
Hermite
1164
Laguerre
1164
Legendre
1164
pop()
of priority_queue
923
of queue
922
of stack
920
pop_back()
container
900
string
1041
pop_front(), list 907
pop_heap()
948
portability
16, 136

–P–

and features
1267
pos_format(), moneypunct 1136
position, bit
978
position(), match_results
1060
positive_sign(), moneypunct 1136
POSIX

880
errc
880
thread support
1192
postcondition
330
pos_type
char_traits
1035
streampos
1035
pow() 1163
valarray
1170
#pragma 341
precedence, operator
255
precondition
56, 330
failure
359
testing
359
predefined
, 531
=
531
&
531
macro
340
meaning for operator
531
predicate
81, 108, 966
concept and
672
type
785
Predicate 716
preempt, thread
1217
preferred locale 1114
prefix
’ 147
$‘ 1061
"
147
0 147
0x 147
L’ 147
L" 147
literal
147
R" 147
return type
308
u’ 147
u" 147
U" 147
U’ 147
u8" 147
prefix(), match_results
1060
premature delete 279
pre-standard implementation
1271
prev(), iterator
959
prev_permutation()
940
primary template
735
principle, zero-overhead
10
print, regex
1054

Index

printf() example
809
priority queue
923
priorityqueue
887
priority_queue
and heap
924
implementation
923
pop() of
923
push() of
923
top() of
923
private member of base class
581
private
:
454, 600
base
605
class member
453
problem
= initialization
492
() initialization
492
procedural programming
11
process
1192
product
dot
1179
inner
1179
program
39
and C++, large
16
large
435, 437
non-C++
442
partitioning of
431, 435
start
441
structure, logical
420
structure, physical 419–420
termination
443
programmer
C#
20
C++
19
C
19
Java
20
programming
31
class-oriented
11
compile-time
780
generative
779
generic
11, 78, 699
ideals
10
meta
779
metaprogramming and
781
multilevel
779
object-oriented
11, 68, 577
paradigm
10
procedural
11
pure functional
780
style
10
style language
17
systems
10, 16
template and generic
665
two-level
779
type-rich
13
value-oriented
478

1327

1328

Index

prohibiting
=
531
, 531
&
531
promise
=
1237
constructor
1237
destructor
1237
future and
120, 1236
get_future()
1237
member set_exception()
120
member set_value() 120
packaged_task and future and
1238
set_exception()
1237
set_exception_at_thread_exit() 1237
set_value()
set_value_at_thread_exit() 1237
swap()
1237
throws future_error
868
promise_already_satisfied 883
promotion
bit-field
267
bool 267
character
267
floating-point
267
integral
267
standard
267
pronunciation, C++
23
propagate_on_∗, allocator_traits 998
propagation, exception 870
protected
:
600
base
605, 618
constructor
1119
member
603–604
protection
454
prvalue
166
pseudo-random number
1180
ptrdiff_t
150, 259, 865
public
:
453–454, 600
class member
453
punct, regex 1054
punctuation
number
1129
of monetary amount
1135
pure
C++
8
functional programming
780
vir tual
65
vir tual function
598
purpose
of namespace 408
template 699
push()
of priority_queue 923

I

of queue
922
of stack
920
push_back()
64, 99
container
900
string
1041
pushback(), vector
385
push_front()
99
list
907
push_heap()
948
put()
iterator, facet
1130
money_put
1138
num_put
1130

Q
qsor t()
334
and exception
352
quadratic time
894
qualification, explicit
588
qualified
{} 287
name
589
name, namespace
392
Quantity
820
queue
deque double-ended
886
priority
923
queue
887
back() of
922
front() of
922
message
922
pop() of
922
push() of
922

863
quick_exit()
443
quiet_NaN()
1161
quote
", double
176
\", double
143
’, single
143
\’, single
143
quotient
1164

R
R"

128, 177
prefix
147
\r, carriage return
143
r, file mode
1254
race, data
115, 1197
RAII
356
constructor destructor
486
lock() and
118
resource acquisition
112

–R–

RAII
64
rand(), random number
1189
Rand_int example
130
RAND_MAX
1189
random
number
939, 1180
number
129
number rand()
1189
number, truly
1185
random
distribution
129
engine
129

129, 865
random-access iterator
955
Random_access_iterator
716
random_access_iterator_tag 956
random_device 1185
random_shuffle() 939
range
access
964
checking
174, 543
checking Vec
97
error
1163
for,
868
for statement
45, 233, 965
half-open
954
of char
141
of enum
223
Range concept
929
rank
1022
ranlux24 1184
ranlux24_base 1184
ranlux48 1184
ranlux48_base 1184
ratio
compile-time arithmetic
1017
SI magnitude
1018

863, 1017
ratio_add 1017
ratio_divide 1017
ratio_equal 1017
ratio_greater
1017
ratio_less 1017
ratio_multiply 1017
rationale, invariant
485
ratio_subtract
1017
raw
storage
1005
string literal
128, 177
string newline
178
raw_storage_iterator
1005
rbegin()
iterator
899
string
1044
read, destructive
194
ready(), match_results 1060

Index

rebind, allocator
997
recompilation
697
recursion
309
class
794
compile-time
793
recursive
descent parser
243
function, exception and
348
lambda
297
recursive_mutex
1223
mutex and
1221
recursive_timed_mutex, timed_mutex and
reduce
1178
reduce()
701
reduction
1178
ref()
968
reference
189
&&, rvalue
75, 194
and object
190
and pointer
189, 196
and template
688
and temporary
191
argument
191, 316
arguments
266
array of
190
call by
191, 316
const
190
constexpr and
312
deduction
688
initialization of
191
lvalue
190
member initialization
495
mutual
571
null
198
return by
310
rvalue
190, 193
to &
45, 190
to class, forward
571
reference
iterator_traits
957
to bit
978
value_type&
896
references, operations on
190
reference_wrapper
968
regex
}
1052
{
1052
$
1052
(
1052
)
1052

1052
|
1052
+
1052
]
1052
[
1052
ˆ
1052

1329

1224

1330

Index

?
1052
=
1057

...
vir tual base
636
representation
array
890
converting character
1146
forward_list 889
list
889
map 889
of container
888
string 890
String 563
unordered_map 889
vector
888
representing memory
379
required
->
758
this->
758
requirement
class vs
...

790
error
55, 344
initialization
442
runtime polymorphism
587
run-time support
15
runtime_error exception
1116
rvalue
166
reference
190, 193
reference && 75, 194
reference argument
317
rvalue-reference deduction
688

S
%s format
1256
\s, regex 1054
s, regex 1054
\S, regex
1054
s, _s vs
...
s
823
safe_assign() 383
safety
convenience vs
...
h>
865
set_symmetric_difference()
947
set_terminate()
372, 872
set_union() 947
set_value()
promise
promise member
120
set_value_at_thread_exit(), promise
1237
SFINAE
691
shadowing, name
158
shallow copy
511
share(), future
1241
shared
implementation
624
interface
624
ownership, shared_ptr
990
state
511
shared_future
1244
shared_ptr
112
<<
992
<=
992
<
992
==
992
>=
992
>
992

992
!=
992
allocateshared() 992
and copy
511
circular structures
991
const_pointer_cast()
992
constructor
992
conversion to bool 992
delays
991
destructor
992
dynamic_pointer_cast()
992
garbage collection 991
get()
992
getdeleter()
992

hash of
915
->m
992
makeshared()
992
nullptr
992
owner_before()
992
reset()
992
shared ownership
990
swap()
992
unpredictable
991
weaknesses
991
sharing data task
117
shift state
1146
shift()
1169
short
namespace name
406
string optimization 561, 563–564
shor t
144
sizeof
150
short-circuit evaluation
229, 260
shrinktofit(), container
898
shrink_to_fit(), string
1040
shuffle()
939
shuffle_order_engine
1184
SI
magnitude ratio
1018
units example
818
sign extension
142
signal
348
...

813
sizeof
char
150
difference from C
1273
double 150
enum
223
enum class
222
float
150
int
150
long
150
long double 150
long long 150
result of
259
shor t
150
sizeof()
124
size_t
83, 150, 259, 865
size_type
896
sleep
1210
sleep_for(), this_thread 1217
sleep_until(), this_thread 1217
slice, generalized
1175
slice
1172
slice(), Matrix
833, 841, 846
slice_array
1174
Slice_iter example
1173
slicing
513
assignment and
513
initialization and
513
smallest int
1161
smart pointer
112, 552, 554
smatch
1060
sort, stable
943
sor t()
102, 942
container
124
Estd
411
example
333, 684
list
907
sor t_heap()
948
source
code, template
695
file
419
space, saving
213
space, regex
1054
special
character
143
function, mathematical
1164

I

operator
549
specialization
742
<> 682
and char∗
736
and overloading
737–738
and void ∗
730
complete
731
consistent
735
explicit
693
function
736
generated
742
hash
915
implementation
734
interface
733
namespace and
736
order of
736
partial
732
pattern
732
template
671, 730
use of
743
user
742
user-defined
730
specialized, more
736
specification
partial
708
throw
367
specifier
153
splice(), list
907
splice_after(), forward_list
908
split() example
394
sqr t()
1163
valarray
1170
srand()
1189
sregex_iterator
1067
sregex_token_iterator
1068

254, 864
stable sort
943
stable_par tition()
940
stable_sor t()
942
stack
allocation, delete
525
frame
167
operation
900
Tuple and
804
unwinding
364, 865
stack
887
implementation
920, 922
overflow
922
pop() of
920
push() of
920
top() of
920
underflow
922

863
standard
currency symbol
1136
facet
1124

–S–

guarantee
135
header must include
866
include directory
424
ISO
135
layout type
211
library
6, 88, 111, 416
library, adding to
866
library algorithm
109
library basic guarantee
868
library, C with Classes
25
library, C++11
29
library, C++98
26
library container
101
library criteria
861
library design
860–861
library exception
868
library facilities
88, 860
library header
89, 428, 863
library, ISO
38
library organization 863
library resource leak
868
library std
89, 863
mathematical functions
1163
promotion
267
vs
...
h>
322, 865
...
h>
865

864
...
h>
863–865, 1164
steady_clock
1016
STL
26
algorithm
927
iterator
954
sequence
954
stod(), string
1042
stof(), string
1042
stoi(), string
1042
stol(), string
1042
stold(), string
1042
stoll(), string
1042
Storable example
632
storage
automatic
167
class
167
free
167
raw
1005
static
167
temporary
167
store
dynamic
63

1335

340

1336

Index

free
63, 167, 277
heap
277
store(), atomic
1200
stoul(), string
1042
stoull(), string
1042
str()
match_results 1060
sub_match 1058
strcpy() string copy
277
stream
864
stream 883
Streamable 716
864
streamoff, off_type
1035
streampos, pos_type 1035
strict weak order
891
stride()
1172
string
"", empty
177
and const, C-style
176
argument, template
724
character
864
comparison
1126
comparison, locale used for
1118
copy, strcpy()
277
C-style
46, 175
format
1255
initialization of array by
176
literal, \
177
literal "
39, 176
literal immutable
176
literal, raw
128, 177
literal, type of
176
locale name
1116
newline, raw
178
optimization, short
561, 563–564
order
1128
size of
318
String
example
668
I/O example
568
representation
563
string 90, 1037
>
1040
>>
1042
>=
1040
[] 1041
=
1039
==
1040
<
1040
<=
1040
<<
1042
+
1041
+=
1041
!=
1040
algorithm and
1044

I

append()
1044
assign()
1044
at()
1041
back()
1041
basic_string
887
begin()
1044
capacity()
1040
cbegin()
1044
cend()
1044
class
561
clear()
1040
compare()
1048
constructor
1039
copy()
1041
crbegin()
1044
crend()
1044
c_str()
1041
data()
1041
destructor
1039
empty()
1040
end()
1044
erase()
1044
find()
1046
find_first_not_of()
1047
find_first_of()
1047
find_last_not_of()
1047
find_last_of()
1047
front()
1041
get_allocator()
1040
getline()
1042
hash of
915
input
93
inser t()
1044
I/O
1042
iterator
1044
length()
1040
locale
1127
max_size()
1040
numeric conversion
1042
output
93
pop_back()
1041
push_back()
1041
rbegin()
1044
rend()
1044
replace()
1045
representation
890
reser ve()
1040
resize()
1040
rfind()
1046
shrink_to_fit()
1040
size()
1040
stod()
1042
stof()
1042
stoi()
1042
stol()
1042
stold()
1042

–S–

stoll()
1042
stoul()
1042
stoull()
1042
subscripting 1041
substr()
1048
swap()
1041
throws length_error
868
throws out_of_range 868
to_string()
1042
to_wstring()
90, 864, 1035–1036
...

17
techniques for exception safety
375
template
literal operator
560
parameter, template and
748
separate compilation of
26
variadic
82
template
31, 78, 668
<> 731, 737
ADL and
754
alias
694
ambiguity
691
and conversion
673
and dependent name
748
and friend
682
and generic programming
665
and inheritance
673
and macro
750
and name of template
748
and namespace
753
and nesting
680
and template parameter
748
and typedef
694
and using
694
argument
722
argument class member
748
argument, deducing
685, 687
argument, default
728
argument, dependency on
746
argument, explicit
686
argument, function
686
argument, int
685
argument, lambda
727
argument local name
748
arguments, inlining
671
as template parameter
727
base class
756
benefits
721
class
78, 670
copy assignment and
679
copy constructor and
679
data member
675
defining a
669
definition check
717
definition, context of
746
error detection
674
function
79, 670, 684
function, vir tual
679
inclusion
695
instantiation
671, 742
instantiation, context of
746

–T–

instantiation directive
744
instantiation, explicit
744
linkage
697
literal type argument
724
Matrix
831
member
670
member alias
676
member, class
675
member function
676
member template
678
member type
677
member typedef
676
member using 676
metaprogramming
779
name binding
745
nested template
678
operation as argument
725
overloading, function
689
parameter
722
parameter, non-type
724
parameter pack
812
parameter, template as
727
parameter, typename and
747
performance
780
pointer argument
724
primary
735
purpose
699
reference and
688
requirement
704
requirements
672
source code
695
specialization
671, 730
static member
676
string argument
724
this and
466
Turing complete
780
type argument
722
type checking
672
type safe
666
type safety
780
value argument
724
variadic
809, 812
temporary
191
elimination of
853
lifetime of
261
object
167, 261
reference and
191
storage
167
value
261
variable
261
tera
1018
terminate program
346
terminate()
372, 872
terminate_handler 372
termination
347
program
443

Index

test(), bitset
980
test_and_set(), atomic_flag
1205
testing
1180
precondition
359

1278
the $ character, $$
1061
this
571
and template
466
lambda
296
this-> required
758
this, self-reference
464
this_thread
get_id()
1217
sleep_for()
1217
sleep_until()
1217
yield()
1217
thousands_sep()
moneypunct
1136
separator character
1129
thread
1191, 1209
support, C-style vs
...
h>
863, 865
timeline, C++
22
time_point 123
!=
1014
+=
1014
>
1014
>=
1014
=
1013
==
1014
-=
1014
1014
<
1014
<=
1014
+
1014
constructor
1013
duration
1013
max()
1014
min()
1014
time_point_cast() 1014
time_since_epoch() 1013
time_point_cast(), time_point 1014
time_since_epoch(), time_point 1013
timing, clock 118
Tiny example
543
tinyness_before 1161
T[n] built-in array
887
to() conversion
730
to_char_type(), char_traits
1035
to_int_type(), char_traits
1035
token, lexical
258
Token example
243
Token_stream example
247
tolower()
1034
ctype 1144
top()
of priority_queue 923
of stack
920
top-down destruction
486
to_string()

I

bitset
980
string
1042
total order
892
Totally_ordered
710, 716
to_time_t(), clock
1015
to_ullong(), bitset
980
to_ulong(), bitset
980
toupper()
1034
ctype
1144
tour of C++
37
to_wstring(), string
Tracer example
483
traditional hierarchy 614
trait
788
alias
788
type function
788
traits
character
1035
overuse of
789
time
1016
transform()
935
collate
1126–1127
regex_traits
1070
transformprimar y(), regex_traits
1070
transition and using directive
416
translate(), regex_traits
1070
translate_nocase(), regex_traits
1070
translation unit
420
transparency, exception
378
traps
1161
treat_as_floating_point
1016
trivial type
211
trivially copyable type
211
true
and 1
139
true_type and
800
truename()
1130
true_type and true
800
truly random number
1185
truncate
270
truncation
270
tr y
block
55, 344
block as function body
98, 371
try-block
378
tr y_lock()
1229
mutex
1221
tr ylock(), timed_mutex
1224
tr y_lock(), unique_lock
1227
tr ylock_for(), timed_mutex
1224
tr y_lock_for(), unique_lock
1227
tr ylock_until(), timed_mutex
1224
tr y_lock_until(), unique_lock
1227
tr y_to_lock_t
1227
Tuple
and stack
804

–T–

element access
806
example
802
get() example
806
index
806
layout
804
list
802
use
804
tuple
127, 815, 984
!= 985
>
985
>=
985
=
985
==
985
<
985
<=
985
<<
817
allocator_arg_t 985
constructor
984
destructor
985
forward_as_tuple() 985
get()
985
maketuple()
985
swap()
985
tie()
985
tuple_cat 985
tuple_elements 985
tuple_size 985
uses_allocator 985

863
tuple_cat, tuple 985
tuple_element, array
977
tuple_elements, tuple 985
tuple\lement, pair
984
tuple_size, array
977
tuplesize, pair
984
tuple_size, tuple 985
Turing complete, template
780
tutorial and manual
3
two-level programming
779
type
40, 138
abstract
65
alias
167, 784
argument, template 722
arithmetic
139
atomic
1200
base
153
built-in
47, 139
char, character
141
character
140, 1035
check, function argument
315
check, return value
309
checking
13
checking, compile-time
13
checking, delayed
784
checking, static
13
checking, template 672

Index

class user-defined
450
closure
297
concrete
60, 470
constructor for built-in
301, 494
conversion
543
conversion, ambiguous
546
conversion, constructor and
538, 543
conversion, explicit
298
conversion, function argument
315
conversion, implicit
150, 267, 544, 575
conversion operator
543
conversion, return value
309
conversion, unions and
214
conversion, user-defined
535, 575, 678
default underlying
219, 223
enum class underlying
219
enum underlying
223
enum user-defined
220
equivalence
210, 673
erasure
733
error
674
floating-point
139, 146
function
124, 781
function, constexpr
786
function, trait
788
function, using
784
fundamental
40, 138
incomplete
205
input of user-defined
94
integer
139, 144
integral
139
literal
264–265
literal of user-defined
540
member
469
move of built-in
516
of {} 289
of integer literal
146
of integer literal, implementation dependency
of lambda
297
of overriding function
596
of string literal
176
ordered
707
output of user-defined
94
parameterized
78
polymorphic
66, 587
predicate
785
regular
706
result
258
return
307–308
reuse of concrete
478
safe, template
666
safety, compile-time
264
safety, template
780
signed
144
size of
40
standard layout
211

1341

146

1342

Index

tag
217
template member
677
trivial
211
trivially copyable
211
typename and name of
747
unsigned 144
user-defined
139, 201
user-defined operator and built-in
value
478
::type
convention
784
delayed checking
784
typedef
alias
168
template and
694
template member
676
type-field
583
typeid() throws bad_typeid 868
type_index and type_info 1030
typeindex, hash of
915
863
type_info, type_index and
1030

865
typename 78, 105

...
using directive
405
directive
394
directive and definition
408
directive, transition and
416
directive, using declaration vs
...

405
template and
694
template member
676
type function
784

I

using
403
vs
...

976
contiguous
886
operation
893
operator=
382
pushback()
385
representation
888
throws out_of_range
868

863
vector_base
379
vector
981
bit order
982
bitset and
977
compactly stored
887
versioning, namespace and
412
vertical tab \v
143
vir tual
65
base class
632
base class, override from
638
base, constructor and
634
base, copy of
510
base layout
633
base, replicated vs
...
h>
864, 1124
wchar t
140
wchar_t
144, 1146
wcmatch
1060
wcregex_iterator
1067
wcregex_token_iterator 1068
weak order, strict
891
weaknesses, shared_ptr
991
weak_ptr
993
=
994
constructor
994
destructor
994
expired() 994
lock()
994
owner_before()
994
reset()
994
swap()
994

I

use_count()
994
Web, C++ and
30
weibull_distribution
1187
WG21
22
what() system_error
878
when to use metaprogramming
794
while statement
44, 236
whitespace, isspace()
250
wide-character literal L’
144
widen(), ctype
1144
Window example
635
word
150
wsmatch
1060
wsregex_iterator
1067
wsregex_token_iterator
1068
wstring
1037
basic_string
887
hash of
915
...
stroustrup