1,687 182 11MB
English Pages [843] Year 2020
Beginning C++20 From Novice to Professional — Sixth Edition — Ivor Horton Peter Van Weert
Beginning C++20 From Novice to Professional Sixth Edition
Ivor Horton Peter Van Weert
Beginning C++20: From Novice to Professional Ivor Horton Stratford-upon-Avon, Warwickshire, UK ISBN-13 (pbk): 978-1-4842-5883-5 https://doi.org/10.1007/978-1-4842-5884-2
Peter Van Weert Kessel-Lo, Belgium ISBN-13 (electronic): 978-1-4842-5884-2
Copyright © 2020 by Ivor Horton and Peter Van Weert This work is subject to copyright. All rights are reserved by the Publisher, whether the whole or part of the material is concerned, specifically the rights of translation, reprinting, reuse of illustrations, recitation, broadcasting, reproduction on microfilms or in any other physical way, and transmission or information storage and retrieval, electronic adaptation, computer software, or by similar or dissimilar methodology now known or hereafter developed. Trademarked names, logos, and images may appear in this book. Rather than use a trademark symbol with every occurrence of a trademarked name, logo, or image we use the names, logos, and images only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark. The use in this publication of trade names, trademarks, service marks, and similar terms, even if they are not identified as such, is not to be taken as an expression of opinion as to whether or not they are subject to proprietary rights. While the advice and information in this book are believed to be true and accurate at the date of publication, neither the authors nor the editors nor the publisher can accept any legal responsibility for any errors or omissions that may be made. The publisher makes no warranty, express or implied, with respect to the material contained herein. Managing Director, Apress Media LLC: Welmoed Spahr Acquisitions Editor: Steve Anglin Development Editor: Matthew Moodie Coordinating Editor: Mark Powers Cover designed by eStudioCalamar Cover image designed by Casey Horner on Unsplash (www.unsplash.com) Distributed to the book trade worldwide by Apress Media, LLC, 1 New York Plaza, New York, NY 10004, U.S.A. Phone 1-800-SPRINGER, fax (201) 348-4505, e-mail [email protected], or visit www.springeronline.com. Apress Media, LLC is a California LLC and the sole member (owner) is Springer Science + Business Media Finance Inc (SSBM Finance Inc). SSBM Finance Inc is a Delaware corporation. For information on translations, please e-mail [email protected]; for reprint, paperback, or audio rights, please e-mail [email protected]. Apress titles may be purchased in bulk for academic, corporate, or promotional use. eBook versions and licenses are also available for most titles. For more information, reference our Print and eBook Bulk Sales web page at www.apress.com/bulk-sales. Any source code or other supplementary material referenced by the author in this book is available to readers on GitHub via the book’s product page, located at www.apress.com/9781484258835. For more detailed information, please visit www.apress.com/source-code. Printed on acid-free paper
This is for Alexander and Henry, who are both going to learn programming soon. If their amazing expertise with Minecraft is anything to go by, they will be brilliant at it. —Ivor Horton For my wonderful family. For all your love and support. —Peter Van Weert
Table of Contents About the Authors�������������������������������������������������������������������������������������������������xxiii About the Technical Reviewer�������������������������������������������������������������������������������xxv Introduction���������������������������������������������������������������������������������������������������������xxvii
■Chapter ■ 1: Basic Ideas������������������������������������������������������������������������������������������� 1 Modern C++��������������������������������������������������������������������������������������������������������������������� 1 Standard Libraries������������������������������������������������������������������������������������������������������������ 2 C++ Program Concepts���������������������������������������������������������������������������������������������������� 3 Source Files�������������������������������������������������������������������������������������������������������������������������������������������� 3 Comments and Whitespace�������������������������������������������������������������������������������������������������������������������� 4 Standard Library Modules���������������������������������������������������������������������������������������������������������������������� 5 Functions������������������������������������������������������������������������������������������������������������������������������������������������ 5 Statements��������������������������������������������������������������������������������������������������������������������������������������������� 6 Data Input and Output���������������������������������������������������������������������������������������������������������������������������� 7 return Statements���������������������������������������������������������������������������������������������������������������������������������� 7 Namespaces������������������������������������������������������������������������������������������������������������������������������������������� 8 Names and Keywords����������������������������������������������������������������������������������������������������������������������������� 8
Classes and Objects��������������������������������������������������������������������������������������������������������� 9 Templates������������������������������������������������������������������������������������������������������������������������� 9 Code Appearance and Programming Style��������������������������������������������������������������������� 10 Creating an Executable�������������������������������������������������������������������������������������������������� 11 Procedural and Object-Oriented Programming�������������������������������������������������������������� 12
v
■ Table of Contents
Representing Numbers��������������������������������������������������������������������������������������������������� 13 Binary Numbers������������������������������������������������������������������������������������������������������������������������������������ 13 Hexadecimal Numbers������������������������������������������������������������������������������������������������������������������������� 15 Negative Binary Numbers��������������������������������������������������������������������������������������������������������������������� 16 Octal Values������������������������������������������������������������������������������������������������������������������������������������������ 18 Big-Endian and Little-Endian Systems������������������������������������������������������������������������������������������������� 18 Floating-Point Numbers������������������������������������������������������������������������������������������������������������������������ 19
Representing Characters������������������������������������������������������������������������������������������������ 21 ASCII Codes������������������������������������������������������������������������������������������������������������������������������������������ 21 UCS and Unicode���������������������������������������������������������������������������������������������������������������������������������� 22
C++ Source Characters�������������������������������������������������������������������������������������������������� 22 Escape Sequences������������������������������������������������������������������������������������������������������������������������������� 23
Summary������������������������������������������������������������������������������������������������������������������������ 25 ■Chapter ■ 2: Introducing Fundamental Types of Data�������������������������������������������� 27 Variables, Data, and Data Types������������������������������������������������������������������������������������� 27 Defining Integer Variables�������������������������������������������������������������������������������������������������������������������� 28 Zero Initialization���������������������������������������������������������������������������������������������������������������������������������� 32 Defining Variables with Fixed Values���������������������������������������������������������������������������������������������������� 32
Integer Literals��������������������������������������������������������������������������������������������������������������� 32 Decimal Integer Literals����������������������������������������������������������������������������������������������������������������������� 32 Hexadecimal Literals���������������������������������������������������������������������������������������������������������������������������� 34 Octal Literals����������������������������������������������������������������������������������������������������������������������������������������� 34 Binary Literals�������������������������������������������������������������������������������������������������������������������������������������� 34
Calculations with Integers���������������������������������������������������������������������������������������������� 35 Compound Arithmetic Expressions������������������������������������������������������������������������������������������������������� 36
Assignment Operations�������������������������������������������������������������������������������������������������� 37 The op= Assignment Operators������������������������������������������������������������������������������������������������������������ 40
The sizeof Operator�������������������������������������������������������������������������������������������������������� 41 Incrementing and Decrementing Integers���������������������������������������������������������������������� 42 Postfix Increment and Decrement Operations�������������������������������������������������������������������������������������� 42 vi
■ Table of Contents
Defining Floating-Point Variables����������������������������������������������������������������������������������� 44 Floating-Point Literals���������������������������������������������������������������������������������������������������� 45 Floating-Point Calculations�������������������������������������������������������������������������������������������� 45 Mathematical Constants����������������������������������������������������������������������������������������������������������������������� 46 Mathematical Functions����������������������������������������������������������������������������������������������������������������������� 47 Invalid Floating-Point Results��������������������������������������������������������������������������������������������������������������� 50 Pitfalls��������������������������������������������������������������������������������������������������������������������������������������������������� 51
Mixed Expressions and Type Conversion������������������������������������������������������������������������ 52 Explicit Type Conversion������������������������������������������������������������������������������������������������� 53 Old-Style Casts������������������������������������������������������������������������������������������������������������������������������������� 56
Formatting Strings��������������������������������������������������������������������������������������������������������� 56 Formatting Stream Output�������������������������������������������������������������������������������������������������������������������� 57 String Formatting with std::format()����������������������������������������������������������������������������������������������������� 57
Finding the Limits����������������������������������������������������������������������������������������������������������� 63 Finding Other Properties of Fundamental Types����������������������������������������������������������������������������������� 64
Working with Character Variables���������������������������������������������������������������������������������� 65 Working with Unicode Characters�������������������������������������������������������������������������������������������������������� 66
The auto Keyword���������������������������������������������������������������������������������������������������������� 67 Summary������������������������������������������������������������������������������������������������������������������������ 68 ■Chapter ■ 3: Working with Fundamental Data Types���������������������������������������������� 71 Operator Precedence and Associativity�������������������������������������������������������������������������� 71 Bitwise Operators����������������������������������������������������������������������������������������������������������� 73 The Bitwise Shift Operators������������������������������������������������������������������������������������������������������������������ 74 Logical Operations on Bit Patterns������������������������������������������������������������������������������������������������������� 77
The Lifetime of a Variable����������������������������������������������������������������������������������������������� 84 Global Variables�������������������������������������������������������������������������������������������������������������� 85 Enumerated Data Types�������������������������������������������������������������������������������������������������� 89 Aliases for Data Types���������������������������������������������������������������������������������������������������� 93 Summary������������������������������������������������������������������������������������������������������������������������ 94 vii
■ Table of Contents
■Chapter ■ 4: Making Decisions������������������������������������������������������������������������������� 97 Comparing Data Values�������������������������������������������������������������������������������������������������� 97 Applying the Comparison Operators����������������������������������������������������������������������������������������������������� 98 Comparing Floating-Point Values������������������������������������������������������������������������������������������������������� 100 The Spaceship Operator��������������������������������������������������������������������������������������������������������������������� 100
The if Statement����������������������������������������������������������������������������������������������������������� 103 Nested if Statements�������������������������������������������������������������������������������������������������������������������������� 107 Character Classification and Conversion�������������������������������������������������������������������������������������������� 108
The if-else Statement��������������������������������������������������������������������������������������������������� 110 Nested if-else Statements������������������������������������������������������������������������������������������������������������������ 112 Understanding Nested ifs������������������������������������������������������������������������������������������������������������������� 113
Logical Operators��������������������������������������������������������������������������������������������������������� 115 Logical AND���������������������������������������������������������������������������������������������������������������������������������������� 115 Logical OR������������������������������������������������������������������������������������������������������������������������������������������� 116 Logical Negation��������������������������������������������������������������������������������������������������������������������������������� 116 Combining Logical Operators������������������������������������������������������������������������������������������������������������� 117 Logical Operators on Integer Operands���������������������������������������������������������������������������������������������� 119 Logical Operators vs. Bitwise Operators�������������������������������������������������������������������������������������������� 119
The Conditional Operator���������������������������������������������������������������������������������������������� 121 The switch Statement�������������������������������������������������������������������������������������������������� 123 Fallthrough����������������������������������������������������������������������������������������������������������������������������������������� 128
Statement Blocks and Variable Scope�������������������������������������������������������������������������� 130 Initialization Statements��������������������������������������������������������������������������������������������������������������������� 131
Summary���������������������������������������������������������������������������������������������������������������������� 132 ■Chapter ■ 5: Arrays and Loops����������������������������������������������������������������������������� 135 Arrays��������������������������������������������������������������������������������������������������������������������������� 135 Using an Array������������������������������������������������������������������������������������������������������������������������������������ 135
Understanding Loops��������������������������������������������������������������������������������������������������� 137 The for Loop����������������������������������������������������������������������������������������������������������������� 138 Avoiding Magic Numbers��������������������������������������������������������������������������������������������� 141 viii
■ Table of Contents
Defining the Array Size with the Braced Initializer������������������������������������������������������� 142 Determining the Size of an Array��������������������������������������������������������������������������������� 143 Controlling a for Loop with Floating-Point Values�������������������������������������������������������� 145 More Complex for Loop Control Expressions���������������������������������������������������������������� 147 The Comma Operator�������������������������������������������������������������������������������������������������������������������������� 148
The Range-Based for Loop������������������������������������������������������������������������������������������� 149 The while Loop������������������������������������������������������������������������������������������������������������� 150 The do-while Loop�������������������������������������������������������������������������������������������������������� 153 Nested Loops���������������������������������������������������������������������������������������������������������������� 155 Skipping Loop Iterations����������������������������������������������������������������������������������������������� 158 Breaking Out of a Loop������������������������������������������������������������������������������������������������� 159 Indefinite Loops���������������������������������������������������������������������������������������������������������������������������������� 159
Controlling a for Loop with Unsigned Integers������������������������������������������������������������� 163 Arrays of Characters����������������������������������������������������������������������������������������������������� 165 Multidimensional Arrays����������������������������������������������������������������������������������������������� 168 Initializing Multidimensional Arrays���������������������������������������������������������������������������������������������������� 170 Multidimensional Character Arrays���������������������������������������������������������������������������������������������������� 173
Allocating an Array at Runtime������������������������������������������������������������������������������������� 174 Alternatives to Using an Array�������������������������������������������������������������������������������������� 177 Using array Containers������������������������������������������������������������������������������������������������������������� 177 Using std::vector Containers�������������������������������������������������������������������������������������������������������� 183
Summary���������������������������������������������������������������������������������������������������������������������� 188 ■Chapter ■ 6: Pointers and References������������������������������������������������������������������ 191 What Is a Pointer?�������������������������������������������������������������������������������������������������������� 191 The Address-Of Operator���������������������������������������������������������������������������������������������� 194 The Indirection Operator����������������������������������������������������������������������������������������������� 195 Why Use Pointers?������������������������������������������������������������������������������������������������������� 197 Pointers to Type char���������������������������������������������������������������������������������������������������� 197 Arrays of Pointers������������������������������������������������������������������������������������������������������������������������������� 200 ix
■ Table of Contents
Constant Pointers and Pointers to Constants��������������������������������������������������������������� 202 Pointers and Arrays������������������������������������������������������������������������������������������������������ 205 Pointer Arithmetic������������������������������������������������������������������������������������������������������������������������������� 205 Using Pointer Notation with an Array Name��������������������������������������������������������������������������������������� 208
Dynamic Memory Allocation����������������������������������������������������������������������������������������� 210 The Stack and the Free Store������������������������������������������������������������������������������������������������������������� 211 Using the new and delete Operators�������������������������������������������������������������������������������������������������� 212 Dynamic Allocation of Arrays�������������������������������������������������������������������������������������������������������������� 213
Member Selection Through a Pointer��������������������������������������������������������������������������� 217 Hazards of Dynamic Memory Allocation����������������������������������������������������������������������� 218 Dangling Pointers and Multiple Deallocations������������������������������������������������������������������������������������ 218 Allocation/Deallocation Mismatch������������������������������������������������������������������������������������������������������ 218 Memory Leaks������������������������������������������������������������������������������������������������������������������������������������ 219 Fragmentation of the Free Store��������������������������������������������������������������������������������������������������������� 219
Golden Rule of Dynamic Memory Allocation���������������������������������������������������������������� 220 Raw Pointers and Smart Pointers�������������������������������������������������������������������������������� 221 Using unique_ptr Pointers����������������������������������������������������������������������������������������������������������� 222 Using shared_ptr Pointers����������������������������������������������������������������������������������������������������������� 225
Understanding References������������������������������������������������������������������������������������������� 229 Defining References��������������������������������������������������������������������������������������������������������������������������� 229 Using a Reference Variable in a Range-Based for Loop��������������������������������������������������������������������� 231
Summary���������������������������������������������������������������������������������������������������������������������� 232 ■Chapter ■ 7: Working with Strings����������������������������������������������������������������������� 235 A Better Class of String������������������������������������������������������������������������������������������������ 235 Defining string Objects����������������������������������������������������������������������������������������������������������������������� 236 Operations with String Objects����������������������������������������������������������������������������������������������������������� 240 Accessing Characters in a String������������������������������������������������������������������������������������������������������� 244 Accessing Substrings������������������������������������������������������������������������������������������������������������������������� 246 Comparing Strings������������������������������������������������������������������������������������������������������������������������������ 247
x
■ Table of Contents
Searching Strings������������������������������������������������������������������������������������������������������������������������������� 255 Modifying a String������������������������������������������������������������������������������������������������������������������������������ 262 std::string vs. std::vector�������������������������������������������������������������������������������������������������������� 267
Converting Strings into Numbers��������������������������������������������������������������������������������� 268 Strings of International Characters������������������������������������������������������������������������������ 268 Strings of wchar_t Characters������������������������������������������������������������������������������������������������������������ 269 Objects That Contain Unicode Strings������������������������������������������������������������������������������������������������ 270
Raw String Literals������������������������������������������������������������������������������������������������������� 271 Summary���������������������������������������������������������������������������������������������������������������������� 272 ■Chapter ■ 8: Defining Functions��������������������������������������������������������������������������� 275 Segmenting Your Programs������������������������������������������������������������������������������������������ 275 Functions in Classes��������������������������������������������������������������������������������������������������������������������������� 276 Characteristics of a Function�������������������������������������������������������������������������������������������������������������� 276
Defining Functions������������������������������������������������������������������������������������������������������� 276 The Function Body������������������������������������������������������������������������������������������������������������������������������ 279 Return Values������������������������������������������������������������������������������������������������������������������������������������� 280 Function Declarations������������������������������������������������������������������������������������������������������������������������� 281
Passing Arguments to a Function��������������������������������������������������������������������������������� 282 Pass-by-Value������������������������������������������������������������������������������������������������������������������������������������� 283 Pass-by-Reference����������������������������������������������������������������������������������������������������������������������������� 291
Default Argument Values���������������������������������������������������������������������������������������������� 298 Multiple Default Parameter Values����������������������������������������������������������������������������������������������������� 299
Arguments to main()����������������������������������������������������������������������������������������������������� 301 Returning Values from a Function�������������������������������������������������������������������������������� 302 Returning a Pointer����������������������������������������������������������������������������������������������������������������������������� 302 Returning a Reference������������������������������������������������������������������������������������������������������������������������ 307 Returning vs. Output Parameters������������������������������������������������������������������������������������������������������� 307 Return Type Deduction������������������������������������������������������������������������������������������������������������������������ 308
Static Variables������������������������������������������������������������������������������������������������������������� 310
xi
■ Table of Contents
Function Overloading��������������������������������������������������������������������������������������������������� 311 Overloading and Pointer Parameters�������������������������������������������������������������������������������������������������� 313 Overloading and Reference Parameters��������������������������������������������������������������������������������������������� 313 Overloading and const Parameters���������������������������������������������������������������������������������������������������� 315 Overloading and Default Argument Values����������������������������������������������������������������������������������������� 317
Recursion��������������������������������������������������������������������������������������������������������������������� 318 Basic Examples of Recursion������������������������������������������������������������������������������������������������������������� 319 Recursive Algorithms�������������������������������������������������������������������������������������������������������������������������� 320
Summary���������������������������������������������������������������������������������������������������������������������� 327 ■Chapter ■ 9: Vocabulary Types����������������������������������������������������������������������������� 333 Working with Optional Values��������������������������������������������������������������������������������������� 333 std::optional���������������������������������������������������������������������������������������������������������������������������������������� 335
String Views: The New Reference-to-const-string������������������������������������������������������� 337 Using String View Function Parameters��������������������������������������������������������������������������������������������� 339 A Proper Motivation���������������������������������������������������������������������������������������������������������������������������� 340
Spans: The New Reference-to-vector or -array����������������������������������������������������������� 340 Spans vs. Views���������������������������������������������������������������������������������������������������������������������������������� 342 Spans of const Elements�������������������������������������������������������������������������������������������������������������������� 342 Fixed-Size Spans�������������������������������������������������������������������������������������������������������������������������������� 343
Summary���������������������������������������������������������������������������������������������������������������������� 344 ■Chapter ■ 10: Function Templates������������������������������������������������������������������������ 347 Function Templates������������������������������������������������������������������������������������������������������ 347 Creating Instances of a Function Template������������������������������������������������������������������ 348 Template Type Parameters������������������������������������������������������������������������������������������� 350 Explicit Template Arguments���������������������������������������������������������������������������������������� 351 Function Template Specialization��������������������������������������������������������������������������������� 351 Function Templates and Overloading��������������������������������������������������������������������������� 352 Function Templates with Multiple Parameters������������������������������������������������������������� 354 Return Type Deduction in Templates���������������������������������������������������������������������������� 355 decltype(auto)������������������������������������������������������������������������������������������������������������������������������������� 356 xii
■ Table of Contents
Default Values for Template Parameters���������������������������������������������������������������������� 357 Non-Type Template Parameters����������������������������������������������������������������������������������� 358 Templates for Functions with Fixed-Size Array Arguments���������������������������������������������������������������� 360
Abbreviated Function Templates���������������������������������������������������������������������������������� 362 Limitations to Abbreviated Function Templates���������������������������������������������������������������������������������� 362
Summary���������������������������������������������������������������������������������������������������������������������� 363 ■Chapter ■ 11: Modules and Namespaces������������������������������������������������������������� 365 Modules������������������������������������������������������������������������������������������������������������������������ 365 Your First Module�������������������������������������������������������������������������������������������������������������������������������� 367 Export Blocks�������������������������������������������������������������������������������������������������������������������������������������� 369 Separating Interface from Implementation���������������������������������������������������������������������������������������� 370 Reachability vs. Visibility�������������������������������������������������������������������������������������������������������������������� 375 Exporting Import Declarations������������������������������������������������������������������������������������������������������������ 376 Managing Larger Modules������������������������������������������������������������������������������������������������������������������ 377 Global Module Fragments������������������������������������������������������������������������������������������������������������������� 381
Namespaces����������������������������������������������������������������������������������������������������������������� 382 The Global Namespace����������������������������������������������������������������������������������������������������������������������� 382 Defining a Namespace����������������������������������������������������������������������������������������������������������������������� 383 Nested Namespaces��������������������������������������������������������������������������������������������������������������������������� 385 Namespaces and Modules����������������������������������������������������������������������������������������������������������������� 386 Functions and Namespaces��������������������������������������������������������������������������������������������������������������� 387 Using Directives and Declarations������������������������������������������������������������������������������������������������������ 389 Namespace Aliases���������������������������������������������������������������������������������������������������������������������������� 391
Summary���������������������������������������������������������������������������������������������������������������������� 391 ■Chapter ■ 12: Defining Your Own Data Types������������������������������������������������������� 395 Classes and Object-Oriented Programming����������������������������������������������������������������� 395 Encapsulation������������������������������������������������������������������������������������������������������������������������������������� 396 Inheritance������������������������������������������������������������������������������������������������������������������������������������������ 399 Polymorphism������������������������������������������������������������������������������������������������������������������������������������� 400
Terminology������������������������������������������������������������������������������������������������������������������ 402 xiii
■ Table of Contents
Defining a Class����������������������������������������������������������������������������������������������������������� 402 Creating Objects of a Class����������������������������������������������������������������������������������������������������������������� 404
Constructors����������������������������������������������������������������������������������������������������������������� 405 Default Constructors��������������������������������������������������������������������������������������������������������������������������� 405 Defining a Class Constructor�������������������������������������������������������������������������������������������������������������� 406 Using the default Keyword����������������������������������������������������������������������������������������������������������������� 408 Defining Functions Outside the Class������������������������������������������������������������������������������������������������� 408 Default Arguments for Constructor Parameters��������������������������������������������������������������������������������� 409 Using a Member Initializer List����������������������������������������������������������������������������������������������������������� 410 Using the explicit Keyword����������������������������������������������������������������������������������������������������������������� 411 Delegating Constructors��������������������������������������������������������������������������������������������������������������������� 413 The Copy Constructor������������������������������������������������������������������������������������������������������������������������� 415
Defining Classes in Modules���������������������������������������������������������������������������������������� 417 Accessing Private Class Members������������������������������������������������������������������������������� 418 The this Pointer������������������������������������������������������������������������������������������������������������ 420 Returning this from a Function����������������������������������������������������������������������������������������������������������� 421
const Objects and const Member Functions���������������������������������������������������������������� 422 const Member Functions�������������������������������������������������������������������������������������������������������������������� 423 const Correctness������������������������������������������������������������������������������������������������������������������������������� 425 Overloading on const�������������������������������������������������������������������������������������������������������������������������� 426 Casting Away const���������������������������������������������������������������������������������������������������������������������������� 427 Using the mutable Keyword���������������������������������������������������������������������������������������������������������������� 428
Friends������������������������������������������������������������������������������������������������������������������������� 429 The Friend Functions of a Class��������������������������������������������������������������������������������������������������������� 429 Friend Classes������������������������������������������������������������������������������������������������������������������������������������ 431
Arrays of Class Objects������������������������������������������������������������������������������������������������ 432 The Size of a Class Object�������������������������������������������������������������������������������������������� 434 Static Members of a Class������������������������������������������������������������������������������������������� 434 Static Member Variables��������������������������������������������������������������������������������������������������������������������� 435 Accessing Static Member Variables��������������������������������������������������������������������������������������������������� 438 Static Constants��������������������������������������������������������������������������������������������������������������������������������� 438 xiv
■ Table of Contents
Static Member Variables of the Class Type Itself�������������������������������������������������������������������������������� 439 Static Member Functions������������������������������������������������������������������������������������������������������������������� 440
Destructors������������������������������������������������������������������������������������������������������������������� 441 Using Pointers as Class Members�������������������������������������������������������������������������������� 444 The Truckload Example����������������������������������������������������������������������������������������������������������������������� 444
Nested Classes������������������������������������������������������������������������������������������������������������� 459 Nested Classes with Public Access���������������������������������������������������������������������������������������������������� 460
Summary���������������������������������������������������������������������������������������������������������������������� 464 ■Chapter ■ 13: Operator Overloading��������������������������������������������������������������������� 467 Implementing Operators for a Class����������������������������������������������������������������������������� 467 Operator Overloading�������������������������������������������������������������������������������������������������������������������������� 468 Implementing an Overloaded Operator����������������������������������������������������������������������������������������������� 468 Nonmember Operator Functions�������������������������������������������������������������������������������������������������������� 471 Implementing Full Support for an Operator���������������������������������������������������������������������������������������� 471
Operators That Can Be Overloaded������������������������������������������������������������������������������ 473 Restrictions and Key Guideline����������������������������������������������������������������������������������������������������������� 474
Operator Function Idioms��������������������������������������������������������������������������������������������� 476 Supporting All Comparison Operators�������������������������������������������������������������������������� 477 Defaulting Comparison Operators������������������������������������������������������������������������������������������������������ 481
Overloading the % : ; . ? * + - / ^ & | ~ ! = , \ ” ’
Chapter 1 ■ Basic Ideas
This is easy and straightforward. You have 96 characters that you can use, and it’s likely that these will accommodate your needs most of the time. Most of the time the basic source character set will be adequate, but occasionally you’ll need characters that aren’t in it. You can, at least in theory, include Unicode characters in a C++ name as well. Which Unicode encoding to use, and which subset of Unicode is supported, depends on your compiler. Both character and string data can similarly include Unicode characters as well. If you want to include a Unicode character in a character or string literal (literals are discussed in Chapter 2), though, in a form that is accepted by any compiler, you should use the hexadecimal representation of its code point. That is: you should then enter it either as \udddd or as \Udddddddd, where d is a hexadecimal digit. Note the lowercase u in the first case and the uppercase U in the second; either is acceptable.
Escape Sequences When you want to use character constants such as a single character or a character string in a program, certain characters are problematic. Obviously, you can’t enter characters such as newline directly as character constants, as they’ll just do what they’re supposed to do: go to a new line in your source code file (the only exception to this rule are raw string literals, which are covered in Chapter 7). You can enter these problem characters in character constants by means of an escape sequence. An escape sequence is an indirect way of specifying a character, and it always begins with a backslash. Table 1-3 shows the most commonly used escape sequences. Table 1-3. The Most Commonly Used Escape Sequences
Escape Sequence
Character
\n
Newline
\r
Carriage return (part of the \r\n newline sequence for Windows)
\t
Horizontal tab
\\
Backslash (\)
\"
Double quote (") in string literals
\'
Single quote (') in character literals
The first three escape sequences in Table 1-3 represent various line break or whitespace characters. The last three characters, however, are more regular characters, yet at times problematic to represent directly in code. Clearly, the backslash character itself is difficult because it signals the start of an escape sequence, and the single and double quote characters because they are used as delimiters for literals, as in the constant 'A' or the string "text". This program that uses escape sequences outputs a message to the screen. To see it, you’ll need to enter, compile, link, and execute the code: // Ex1_02.cpp // Using escape sequences import ; int main() { std::cout > 4) & ~(~0u -8 i second; std::cout 8} {:>8} {:>20}\n"; // Output column headings std::cout 8}", '|'); for (auto w : weight_lbs) std::cout " push_back(66); // Add an element containing 66 The -> operator is formed by a minus sign and a greater-than character and is referred to as the arrow operator or indirect member selection operator. The arrow is much more expressive of what is happening here. You’ll be using this operator extensively later in the book.
Hazards of Dynamic Memory Allocation There are many kinds of serious problems you may run into when you allocate memory dynamically using new. In this section, we name the most common ones. Unfortunately, these hazards are all too real, as any developer who has worked with new and delete will corroborate. As a C++ developer, a significant portion of the more serious bugs you deal with often boil down to mismanagement of dynamic memory. In this section, we will thus paint you a seemingly very bleak picture, filled with all kinds of hazards of dynamic memory. But don’t despair. We will show you the way out of this treacherous minefield soon enough! Right after this section we will list the proven idioms and utilities that actually make it easy for you to avoid most if not all of these problems. In fact, you already know about one such utility: the std::vector container. This container is almost always the better choice over allocating dynamic memory directly using new[]. Other facilities of the Standard Library to better manage dynamic memory are discussed in upcoming sections. But first let’s dwell on all these lovely risks, hazards, pitfalls, and other perils alike that are associated with dynamic memory.
Dangling Pointers and Multiple Deallocations A dangling pointer, as you know, is a pointer variable that still contains the address to free store memory that has already been deallocated by either delete or delete[]. Dereferencing a dangling pointer makes you read from or, often worse, write to memory that might already be allocated to and used by other parts of your program, resulting in all kinds of unpredictable and unexpected results. Multiple deallocations, which occur when you deallocate an already deallocated (and hence dangling) pointer for a second time using either delete or delete[], is another recipe for disaster. We taught you one basic strategy already to guard yourself against dangling pointers, that is, to always reset a pointer to nullptr after the memory it points to is released. In more complex programs, however, different parts of the code often collaborate by accessing the same memory—an object or an array of objects—all through distinct copies of the same pointer. In such cases our simple strategy rapidly falls short. Which part of the code is going to call delete/delete[]? And when? That is, how do you be sure that no other part of the code is still using the same dynamically allocated memory?
Allocation/Deallocation Mismatch A dynamically allocated array, allocated using new[], is captured in a regular pointer variable. But so is a single allocated value that is allocated using new: int* single_int{ new int{123} }; // Pointer to a single integer, initialized with 123 int* array_of_ints{ new int[123] }; // Pointer to an array of 123 uninitialized integers
218
Chapter 6 ■ Pointers and References
After this, the compiler has no way to distinguish between the two, especially once such a pointer gets passed around different parts of the program. This means that the following two statements will compile without error (and in many cases even without a warning): delete[] single_int; // Wrong! delete array_of_ints; // Wrong! What’ll happen if you mismatch your allocation and deallocation operators depends entirely on the implementation associated with your compiler. But it won’t be anything good.
■■Caution Every new must be paired with a single delete; every new[] must be paired with a single delete[]. Any other sequence of events leads to either undefined behavior or memory leaks (discussed next).
Memory Leaks A memory leak occurs when you allocate memory using new or new[] and fail to release it. If you lose the address of free store memory you have allocated, by overwriting the address in the pointer you were using to access it, for instance, you have a memory leak. This often occurs in a loop, and it’s easier to create this kind of problem than you might think. The effect is that your program gradually consumes more and more of the free store, with the program potentially slowing more and more down, or even failing at the point when all of the free store has been allocated. When it comes to scope, pointers are just like any other variable. The lifetime of a pointer extends from the point at which you define it in a block to the closing brace of the block. After that it no longer exists, so the address it contained is no longer accessible. If a pointer containing the address of a block of memory in the free store goes out of scope, then it’s no longer possible to delete the memory. It’s still relatively easy to see where you’ve simply forgotten to use delete to free memory when use of the memory ceases at a point close to where you allocated it, but you’d be surprised how often programmers make mistakes like this, especially if, for instance, return statements creep in between the allocation and deallocation of your variable. And, naturally, memory leaks are even more difficult to spot in complex programs, where memory may be allocated in one part of a program and should be released in a completely separate part. One basic strategy for avoiding memory leaks is to immediately add the delete operation at an appropriate place each time you use the new operator. But this strategy is by no means fail-safe. We cannot stress this enough: humans, even C++ programmers, are fallible creatures. So, whenever you manipulate dynamic memory directly, you will, sooner or later, introduce memory leaks. Even if it works at the time of writing, all too often bugs find their way into the program as it evolves further. return statements are added, conditional tests change, exceptions are thrown (see Chapter 16), and so on. And all of a sudden there are scenarios where your memory is no longer freed correctly!
Fragmentation of the Free Store Memory fragmentation can arise in programs that frequently allocate and release memory blocks. Each time the new operator is used, it allocates a contiguous block of bytes. If you create and destroy many memory blocks of different sizes, it’s possible to arrive at a situation in which the allocated memory is interspersed with small blocks of free memory, none of which is large enough to accommodate a new memory allocation
219
Chapter 6 ■ Pointers and References
request by your program. The aggregate of the free memory can be quite large, but if all the individual blocks are small (smaller than a current allocation request), the allocation request will fail. Figure 6-6 illustrates the effect of memory fragmentation.
Memory blocks that have been released but are smaller than the next block requested to be allocated. The total amount of free memory may be large, but it's all in small blocks.
A new block of memory is requested that is much smaller than the total memory that is free, but it cannot be allocated because it's larger than any available block.
Rest of the Free Store Fragmented in Same way.
Memory Allocated and Still in Use Figure 6-6. Fragmentation of the free store We mention this problem here mostly for completeness because it arises relatively infrequently these days. Virtual memory provides a large memory address space even on quite modest computers. And the algorithms behind new/delete are clever and designed to counteract such phenomena as much as possible. It’s only in rare cases that you need to worry about fragmentation anymore. For instance, for the most performance-critical parts of your code, operating on fragmented memory may seriously degrade performance. The way to avoid fragmentation of the free store then is not to allocate many small blocks of memory. Allocate larger blocks and manage the use of the memory yourself. But this is an advanced topic, well outside the scope of this book.
Golden Rule of Dynamic Memory Allocation After spending more than half a dozen pages learning how to use the new and delete operators, our golden rule of dynamic memory allocation may come as a bit of a surprise. It’s nevertheless one of the single most valuable pieces of advice we give you in this book:
■■Tip Never use the operators new, new[], delete, and delete[] directly in day-to-day coding. These operators have no place in modern C++ code. Always use either the std::vector container (to replace dynamic arrays) or a smart pointer (to dynamically allocate individual objects and manage their lifetimes). These high-level alternatives are much, much safer than the low-level memory management primitives and will help you tremendously by eradicating dangling pointers, multiple deallocations, allocation/deallocation mismatches, and memory leaks from your programs. 220
Chapter 6 ■ Pointers and References
The std::vector container you already know from the previous chapter, and smart pointers are explained in the next section. The main reason we still teach you about the low-level dynamic memory allocation primitives is not because we’d invite you to use them (often or at all), but because you will surely still encounter them in existing code. This also, unfortunately, implies that you will be tasked with fixing bugs caused by their use. (Bonus tip: a good first step would be to rewrite this code using better, more modern memory management utilities; more often than not, the underlying problem then reveals itself.) In your own code, you should normally avoid manipulating dynamic memory directly.
Raw Pointers and Smart Pointers All the pointer types we have discussed up to now are part of the C++ language. These are referred to as raw pointers because variables of these types contain nothing more than an address. A raw pointer can store the address of an automatic variable or a variable allocated in the free store. A smart pointer is an object that mimics a raw pointer in that it contains an address, and you can use it in the same way in many respects. Smart pointers are normally used only to store the address of memory allocated in the free store. A smart pointer does much more than a raw pointer, though. By far the most notable feature of a smart pointer is that you don’t have to worry about using the delete or delete[] operator to free the memory. It will be released automatically when it is no longer needed. This means that multiple deallocations, allocation/deallocation mismatches, and memory leaks will no longer be possible. If you consistently use smart pointers, dangling pointers will be a thing of the past as well. Smart pointers are particularly useful for managing class objects that you create dynamically, so smart pointers will be of greater relevance from Chapter 12 on. You can also store them in an array or vector container, which is again very useful when you are working with objects of a class type. Smart pointer types are defined by templates inside the module of the Standard Library, so you must import this module in your source file to use them. There are three types of smart pointers, all defined in the std namespace: •
A unique_ptr object behaves as a pointer to type T and is “unique” in the sense that there can be only one single unique_ptr object containing the same address. In other words, there can never be two or more unique_ptr objects pointing to the same memory address at the same time. A unique_ptr object is said to own what it points to exclusively. This uniqueness is enforced by the fact that the compiler will never allow you to copy a unique_ptr.2
•
A shared_ptr object also behaves as a pointer to type T, but in contrast with unique_ ptr there can be any number of shared_ptr objects that contain—or, share—the same address. Thus, shared_ptr objects allow shared ownership of an object in the free store. At any given moment, the number of shared_ptr objects that contain a given address in time is known by the runtime. This is called reference counting. The reference count for a shared_ptr containing a given free store address is incremented each time a new shared_ptr object is created containing that address, and it’s decremented when a shared_ptr containing the address is destroyed or assigned to point to a different address. When there are no shared_ptr objects containing a given address, the reference count will have dropped to zero, and the memory for the object at that address will be released automatically. All shared_ptr objects that point to the same address have access to the count of how many there are. You’ll understand how this is possible when you learn about classes in Chapter 12.
In Chapter 18, you’ll learn that while copying a unique_ptr is not possible, you can “move” the address stored by one unique_ptr object to another by using the std::move() function. After this move operation the original smart pointer 2
will be empty again.
221
Chapter 6 ■ Pointers and References
•
A weak_ptr is linked to a shared_ptr and contains the same address. Creating a weak_ptr does not increment the reference count associated with the linked shared_ptr object, though, so a weak_ptr does not prevent the object pointed to from being destroyed. Its memory will still be released when the last shared_ptr referencing it is destroyed or reassigned to point to a different address, even when associated weak_ptr objects still exist. If this happens, the weak_ptr will nevertheless not contain a dangling pointer, at least not one that you could inadvertently access. The reason is that you cannot access the address encapsulated by a weak_ptr directly. Instead, the compiler will force you to first create a shared_ptr out of it that refers to the same address. If the memory address for the weak_ptr is still valid, forcing you to create a shared_ptr first ensures that the reference count is again incremented and that the pointer can be used safely again. If the memory is released already, however, this operation will result in a shared_ptr containing nullptr.
One use for having weak_ptr objects is to avoid so-called reference cycles with shared_ptr objects. Conceptually, a reference cycle is where a shared_ptr inside an object x points to some other object y that contains a shared_ptr, which points back to x. With this situation, neither x nor y can be destroyed. In practice, this may occur in ways that are more complicated. weak_ptr smart pointers allow you to break such reference cycles. Another use for weak pointers is the implementation of object caches. However, as you no doubt already started to sense, weak pointers are used only in more advanced use cases. As they are used only sporadically, we’ll not discuss them any further here. The other two smart pointer types, however, you should use literally all the time, so let’s dig a bit deeper into them.
Using unique_ptr Pointers A unique_ptr object stores an address uniquely, so the value to which it points is owned exclusively by the unique_ptr smart pointer. When the unique_ptr is destroyed, so is the value to which it points. Like all smart pointers, a unique_ptr is most useful when working with dynamically allocated objects. Objects then should not be shared by multiple parts of the program or where the lifetime of the dynamic object is naturally tied to a single other object in your program. One common use for a unique_ptr is to hold something called a polymorphic pointer, which in essence is a pointer to a dynamically allocated object that can be of any number of related class types. To cut a long story short, you’ll only fully appreciate this smart pointer type after learning all about class objects and polymorphism in Chapters 12 through 15. For now, our examples will simply use dynamically allocated values of fundamental types, which do not really excel in usefulness. What should become obvious already, though, is why these smart pointers are that much safer to use than the low-level allocation and deallocation primitives; that is, they make it impossible for you to forget or mismatch deallocation! In the (not so) old days, you had to create and initialize a unique_ptr object like this: std::unique_ptr pdata {new double{999.0}}; This creates pdata, which contains the address of a double variable in the free store that is initialized with 999.0. While this syntax remains valid, the recommended way to create a unique_ptr today is by means of the std::make_unique() function template (introduced by C++14). To define pdata, you should therefore normally use the following: std::unique_ptr pdata { std::make_unique(999.0) };
222
Chapter 6 ■ Pointers and References
The arguments to std::make_unique(...) are exactly those values that would otherwise appear in the braced initializer of a dynamic allocation of the form new T{...}. In our example, that’s the single double literal 999.0. To save you some typing, you’ll probably want to combine this syntax with the use of the auto keyword: auto pdata{ std::make_unique(999.0) }; That way, you only have to type the type of the dynamic variable, double, once.
■■Tip To create a std::unique_ptr object that points to a newly allocated T value, always use the std::make_unique () function. You can dereference pdata just like an ordinary pointer, and you can use the result in the same way: *pdata = 8888.0; std::cout >= 15}", word); if (!(++count % 5)) std::cout when accessing a member. The compiler takes care of that for you. Together with the this pointer, you can still capture other variables as well. You can combine this with a & or = capture default and/or any sequence of captures of named variables. Examples of such capture clauses are [=, this], [this, &counter] , and [x, this, &counter].
■■Caution The = capture default technically still implies that the this pointer is captured, but this behavior was deprecated in C++20 and should no longer be relied upon. That is, in older code, you may still encounter expressions such as this: return *findOptimum(values, [=](double x, double y) {// Also captures this (deprecated) return std::abs(x - m_number_to_search_for) < std::abs(y - m_number_to_search_for); });
In C++20 code you should always capture the this pointer explicitly, never implicitly through = (your compiler will likely warn you if you do not).
The std::function Template The type of a function pointer is very different from that of a function object or lambda closure. The former is a pointer, and the latter is a class. At first sight, it might thus seem that the only way to write code that works for any conceivable callback—that is, a function pointer, function object, or lambda closure—is to use either auto or a template type parameter. This is what we did for our findOptimum() template in earlier examples. The same technique is heavily used throughout the Standard Library, as you will see in the next chapter.
735
Chapter 19 ■ First-Class Functions
Using templates does have its cost. You risk template code bloat, where the compiler has to generate specialized code for all different types of callbacks, even when it’s not required for performance reasons. It also has its limitations: What if you needed say a vector of callback functions—a vector that is potentially filled with a mixture of function pointers, function objects, and lambda closures? To cater to these types of scenarios, the module defines the std::function template. With objects of type std::function you can store, copy, move, and invoke any kind of function-like entity—be it a function pointer, function object, or lambda closure. The following example demonstrates precisely that: // Ex19_08.cpp // Using the std::function template import ; import ; #include // for std::abs() // A global less() function bool less(int x, int y) { return x < y; } int main() { int a{ 18 }, b{ 8 }; std::cout