The C++ Programmign Language - Bjarne Stroustrup
I didn’t know that the author considers programmers using older versions of c++ to be programming lower-quality code. The prefaces remind me of all the things I take for granted in c++ that are not available in c. In chapter 1 the overview of all of the things listed in the book looks surprisingly unfamiliar, how exciting. I didn’t know the purpose of c++ was to be close to the machine and close to the problem to be solved. I didn’t know that c++ was designed with the zero-overhead principle in mind. I am not certain what generic programming is or how it is different from procedural programming. What is a class lattice? It is interesting to learn the thought process of Stroustrup when creating c++.
The first chapter provides good context on not only what c++ is, but how to use it. Are there other languages that are not compiled languages? If so how do they work? What does a unary plus do? I didn’t know you can initialize variables with curly braces. I didn’t know we can use auto to initialize primitive data types. I didn’t know that when you use & in a declaration it means in reference to and it is basically like a pointer but you don’t need the * prefix.
I didn’t know you can define operators for enumerations. I didn’t know that namespaces are used to make sure your own function names don’t interfere with other libraries functions. Do static assertions or exception handling slow down runtime? How does the compiler inline functions? So are concrete types just the classes I have been familiar with in 281?
This section reminds me that c++ is nice in the way that we don’t have to worry about allocating the memory in a vector or some other container because the vector class takes care of that for us. What is a move constructor? I didn’t know that concrete types representation is part of their definition. I didn’t know that abstract types completely insulate a user from implementation details. I didn’t know that virtual meant may be redefined later in a class derived from this one. I didn’t know that a class derived from an abstract class must define the abstract class’s pure virtual functions. I didn’t know that a class that provides interface to other classes is a polymorphic type. I didn’t know about virtual function tables, but it seems good that virtual function calls are within 25% as fast as normal function calls. What is a unique_ptr and how do they automatically delete our objects? So the compiler automatically knows when to use a move constructor? I didn’t know we can delete the default copy and move operations. I didn’t know that templates incur no run-time overhead compared to hand-crafted code. How does a compiler handle templates at compile-time? I didn’t know you could parameterize types and algorithms. I didn’t know that function objects that specify a key operations of an algorithm are referred to as policy objects. I didn’t know there is a notation for implicitly generating function objects. I didn’t know we could use [&] to specify a capture list for local names to be used through reference or that we could do the same thing by value. Is a variadic template similar to the printf function in c? What exactly is a namespace?
C++ strings seem much better to work with than C-style strings. I didn’t know that whitespace terminates the read input. I didn’t know how much harder it was to make input operator for user-defined types compared to output operators. I didn’t know the .at() operation was just a subscript with range checking. Iterators seem smart because they allow us to iterate over any container with a begin and end iterator. So a map is an AVL tree? How do the unordered containers differ from each other? I didn’t know that a sequence is represented by a pair of begin and end iterators. I didn’t know that I can define container versions of the algorithms to eliminate the need for begin and end every time I call an STL algorithm. What exactly is an iterator under the hood? Iterators are pretty smart, since we can use them to traverse a container and hide the implementation details to what the iterator actually is. I didn’t know we can use iterators to write to cout or other output streams. I didn’t know we can provide arguments to the output stream iterator to delimit output values. What is a mutex? I didn’t know that unique_ptr has no space or time overhead compared to normal pointers. How is a shared_ptr not cost free? I didn’t know there were stl functions that measured time. I didn’t know a type function is a function evaluated at compile-time, given or returning a type. I didn’t know there are iterators that only go forwards. Is it bad practice to access an iterators member value_type directly instead of using an alias? I didn’t know something like tuple exists where we can have a heterogenous sequence of elements. I didn’t know the stl had regular expressions. I didn’t know the stl had so many functions for mathematical computations. So the function bind() kind of acts like an alias creator for function objects? I didn’t know that you can choose your own distribution for a random number generator in c++.
I didn’t know there was a global namespace where names reside if you don’t specifically put them in a namespace. What do you do if two libraries have the same name for their namespace? I didn’t know that you can use only one name in a namespace if you want to suchs as using std::cout. I didn’t know narrowly-scoped namespaces are okay for header files. I didn’t know that you shouldn’t put using above a #include because that is basically the same thing as putting that using in the #include header file.
I don’t exactly understand what a freestanding implementation is? I didn’t know you can map the extended character set to a basic character set. I didn’t know that boolean, characters, and integers are called integral types. I didn’t know you can add and subtract bools. I didn’t know a pointer can be implicitly converted into a bool. I didn’t know there are 6 different types of chars. I didn’t know the sign of a default char is implementation defined. I didn’t know you can’t mix pointers to different kinds of chars. I didn’t know that different machines have different character sets. Is unicode just a different character set than ascii? What happens if we have to store extremely large numbers that can not be held in a long long or in a double? I didn’t know that decimals, hexadecimal, and octal are just integer literals. I didn’t know a float was just a double, but with less precision. I didn’t know there are suffixes for floating point literals. I didn’t know there are infixes and prefixes for the different data types either. I didn’t know we can define new suffixes for user-defined types. I didn’t know that it is not guaranteed that the size of a long is less than the size of a long long. I didn’t know the stl contains functions for alignment. So extern int error_number; extern int error_number has no errors since it is defined in some other file? I didn’t know that declaration operators only apply to individual names and not to the entire declaration. I didn’t know that c++ imposes no limit on the number of characters in a name, but a linker might. I didn’t know that certain variable names are reserved. I didn’t know that from a large scope names should have long and reasonably obvious names. I didn’t know that I wasn’t supposed to encode type information in a name. I didn’t know namespace scope was a thing. I didn’t know that global scope was just the global namespace scope. I didn’t know a hidden global name can be referred to with the scope resolution operator. I didn’t know that a name can be used to specify its own initial value. I didn’t know that the initializer list does not allow for narrowing. I didn’t know that most types have a default value. I didn’t know there was a difference in missing initializers for local and static objects. I didn’t know that decItype can be used to deduce the return type of a function. I am confused about how an rvalue does not have an identity. I didn’t know we can not apply type specifiers to an alias. I didn’t know that a pointer to a function of a member cannot be assigned type void. I didn’t know that the only operations you can do on a void pointer is check for equality/inequality and converted to another pointer type. I didn’t know that there was just one nullptr type. I didn’t know that there are differences in NULL and nullptr. I didn’t know that the number of elements of an array must be a constant expression. I didn’t know you can allocate an array on the free store. I didn’t know that if the initializer supplies too few elements for an array 0 is used for the rest. I didn’t know a string literal is an array of the appropriate number of const characters. Raw string literals seem good when we need a lot of backslashes. What is the difference between the different utf encodings? I didn’t know that a[j] == j[a]. I didn’t know subtraction of pointers is only defined for pointers to the same array. I didn’t know there is no way to pass an array by value. Section 7.5 cleared up the difference between a pointer to a const and a const pointer. Is a reference not just a constant pointer to an object? So references cannot change the object to which they are referencing? I didn’t know that we can not have an array of references. Couldn’t an lvalue reference refer to a temporary object? I didn’t know that rvalue references have a different syntax than lvalue references. If an object can not use move operations will the copy operation automatically happen instead? I didn’t know that reference to reference can only happen using an alias or template type. I didn’t know that a reference is not an object. I didn’t know a union is a struct that holds the value of just one of its elements at any time. How does a struct differ from a tuple? I didn’t know that to maximize space we should order members by largest to smallest. We can declare names of structs so that other structs can use the name even if the struct is not defined yet. I didn’t know that it is possible to declare a struct and a non-struct with the same name in the same scope. I didn’t know that a struct was just a class where the members are public by default. I didn’t know that two structs are different types even if they have the same members. Why does a struct require a trivial default constructor to be a POD? I didn’t know bitfields existed and that I could make it so a bool only takes up 1 bit. I didn’t know unions only occupy as much space as its largest member. I didn’t know you can explicitly state the underlying type for an enum class. I didn’t know that the compiler might be able to spot warnings if you use an enum instead of say an int. I didn’t know that you can define operators for your enum class. I didn’t know we can declare an enum class without defining it until later. I didn’t know the sizeof an enum class is the size of its underlying type. I didn’t know that for plain enums you can’t declare them later unless you specify the enums underlying type. I didn’t know a plain enum can be unnamed. I didn’t know that an expression becomes a statement when you add a semicolon to the end. I didn’t know that a semicolon by itself is a statement. You usually don’t need a variable until you want to assign it a value. How could a condition be a declaration? I didn’t know that a plain enum can be converted to an integer and then to a bool. What is a jump table? I didn’t know that I should leave out default in a switch if I have a switch for each case of an enumeration. I didn’t know that you can’t declare variables in switch cases, but then why can you do it in if statements? I didn’t know that a variable declared in an if condition had a scope to the other branches. Can a range for be used for reverse iterators? It is interesting that Stroustrup recommends avoiding do statements. I didn’t know that you can use a goto to jump into and out of blocks. Bad comments can be worse than no comments. I didn’t know that a token is a {kind-of-token, value} pair. I’m confused about the purpose of prim. It makes sense to put an assignment and return together so that if one is changed you don’t need to look through code to change the other. What is a table lookup? I didn’t know that using a short string doesn’t require and use of free store. Why would we want to separate error detection from error recovery? Why is the convention for calling main the same between c and c++. What is a capture-list? What are context dependencies? I didn’t know that unary and assignment operators are the only ones that are right-associative. I didn’t know that there are alternative representations of some symbols. I didn’t know that if you increase an integer’s value enough its value will wrap around. I didn’t know that the evaluation of subexpressions is undefined. I didn’t know that you can use a comma to guarantee certain evaluations. I didn’t know that a compiler uses temporary variables under the hood for certain expressions. I didn’t know the errors that can happen if you don’t account for the compilers temporary variable. I didn’t know that some addresses can be used in some forms of constant expressions. I didn’t know we can use constant expressions to have compile-time functions. We should use symbolic names to avoid “magic numbers”. I didn’t know a const initialized with a constant expression can be used in a constant expression. I didn’t know that a class with a constant expression constructor is called a literal type. I didn’t know that constexpr cannot deal with references but can deal with constant addresses. I didn’t know that implicit conversions that preserve values are called promotions. I didn’t know there are run-time checked conversion functions. I didn’t know about all the things that happen under the hood when converting to signed or unsigned types. I didn’t know that a pointer to a function or a pointer to a member cannot be implicitly converted to void. What about explicitly? I didn’t know the ! operator applies to pointer types. I didn’t know we can combine bit operators with the = sign. I didn’t know that conditional expression can be used in constant expressions. I didn’t know that when using new on built-in types they are uninitialized by default. I didn’t know double deletion was a problem when managing memory. Try to avoid naked news and deletes. Why do we have to differentiate between delete and delete[]? I didn’t know that using new and delete will occupy slightly more space than static objects. I didn’t know we can define a new handler to do something upon memory exhaustion. I didn’t know that every operator new() takes a size as its first argument which is implicitly supplied. I didn’t know we can overload the new operator to specify where we get the memory from. I didn’t know that nothrow was the name of an object in the standard-library. I didn’t know the underlying operations of using an initializer list change depending on the context. I didn’t know an unqualified list is used where an expected type is unambiguously used. How are lambdas more useful than declaring a function object? I didn’t know that an object of a class generated from a lambda is called a closure object. I didn’t know that you can name lambdas. I didn’t know that we don’t have to capture global or namespace variables. I didn’t know that this is always passed by reference. I didn’t know that the rules for passing arguments to a lambda and the return rules are almost the same as functions. I didn’t know there are different kinds of casts. I didn’t know the c-style cast was more dangerous than the named conversion operators. I didn’t know that implicit type conversion takes place when necessary to function arguments. What is a linkage specification? I didn’t know there are so many specifications for member functions. What is a volatile object? I didn’t know you can indicate that an argument is unused by not naming it in the function definition. I didn’t know you can place the return type after a function’s argument list. I didn’t even know you can program functions that have return types dependent on the function arguments. I didn’t know a call of a void function can be used as the return value of a void function. I didn’t know that inline functions attempt to generate code for a call of a function. I didn’t know a constexpr function must consist of a single return statement. I didn’t know that a branch not taken in a constexpr can require run-time evaluation. I didn’t know that a static variable preserved information between function calls. I didn’t know it is undefined if you declare a static local variable recursively. I didn’t know that literals require the function argument to be const. I didn’t know we can pass rvalues by reference to functions. I didn’t know you can declare a parameter of type reference to array. I didn’t know initializer_list arguments have priority over other arguments. I didn’t know that if you use the ellipsis then you need to call va_start() and at the end of the function va_end(). I didn’t know default arguments may be provided for trailing arguments only. I didn’t know the compiler tried different criteria to determine which function to use. I didn’t know that return types are not taken into account during overloading resolution. I didn’t know that we can do manual overload resolution. Good reminder that users of an implementation will frequently not use it right. I didn’t know that a pointer to a function does not allow the code to be modified. I didn’t know that macros are only recommended for use for conditional compilation and for include guards. I didn’t know that macro names cannot be overloaded. I didn’t know macros can be variadic. I didn’t know there are predefined macros.
I didn’t know the exception-handling mechanism is integrated with the constructor/destructor mechanisms. I didn’t know an exception is an object. I didn’t know c had a nonlocal variable errno to indicate an error. I didn;t know an uncaught exception will always terminate or a noexcept specifier. I didn’t know asynchronous events are not handled by exceptions. I didn’t know you can use exception-handling outside of error-handling. I didn’t know there are other error-handling methods besides exceptions. I didn’t know we can go from one type of error-handling to another. I didn’t know that throwing an exception is not much more expensive than a function call. I didn’t know an operation is called exception-safe if that operation leaves the program in a valid state when the operation is terminated by throwing an exception. I didn’t know that the standard library has such guarantees about invariants and operations. I didn’t know it was possible to catch every possible exception with the … . I didn’t know that it is important to release resources in the reverse order of their acquisition. I didn’t know there are compile-time asserts. I didn’t know you can only throw an error that can be copied or moved. I didn’t know that passing the exception up the stack is known as stack unwinding. I didn’t know it is possible to declare a function to be conditionally noexcept. I didn’t know that there are exception specifications. I didn’t know we can catch exceptions by reference. I didn’t know a rethrow is indicated by a throw without an operand. I didn’t know there is an exception to catch every standard library exception. I didn’t know the compiler knows about the class hierarchy. I didn’t know the body of a function can be a try block. I didn’t know that you shouldn’t throw an exception while handling an exception. I’ve never thought of a type as a concrete representation of a concept. I didn’t know that a class is a namespace. I didn’t know that by default the copy of a class is a copy of each of its members. I didn’t even consider that classes might be useful for localizing bugs. I didn’t know that by default members of a class are private. I didn’t know access specifiers can be used multiple times in a class declaration. I didn’t know that when an argument value is used to indicate “pick the default” the value must be chosen outside of the set of possible values. I didn’t know that we can avoid implicit conversion for constructors by using the explicit keyword. I didn’t know explicit initialization is known as direct initialization. I didn’t know that if a constructor is declared explicit and defined outside the class the explicit cannot be repeated. I didn’t know we can use an extra struct to initialize members. I didn’t know that a member function declared inside of a class is taken to be an inline member function. I didn’t know the const after the function argument list indicates that the function does not modify anything. I didn’t know logical constness is a thing. I didn’t know that mutable makes it so even a member of a class can be modified in a const. I didn’t know that it can be useful to return a reference to an object so that the operations can be chained. I didn’t know that this is a rvalue. I didn’t know that explicit use of this is required for access to members of base class from a derived class that is a template. I didn’t know that there is exactly one copy of a static member instead of one copy per object. I didn’t know that a function that needs access to members of a class but doesn’t need to be invoked is called a static member function. I didn’t know types and aliases can be members of a class. I didn’t know that a nested class have no notion of the outside class. I didn’t know concrete classes are preferred for small, frequently used types. I didn’t know that member functions can rely on the constructors invariant. How do multiple constructors increase performance compared to the single constructor with default argument? I didn’t know that we shouldn’t define certain functions in the class itself because it would complicate the class interface. I didn’t know that copy initialization was provided by default. I didn’t know concrete types are also known as value types. I didn’t know that concrete types aren’t supposed to display run-time polymorphic behavior. Would we ever use an incomplete declaration in a .cpp file? I didn’t know we should use an incomplete declaration in a header file whenever possible. I didn’t know an incomplete declaration will work in a header file if class X only appears as a return or as an argument, if class X is only referred to by a pointer or reference, or if X is an opaque type member variable. I didn’t know that we cannot use an incomplete declaration if we don’t actually know the name of the type. I didn’t know we can use forward declarations to make classes that rely on each other to compile correctly. I didn’t know that the main module usually does not have a header file. I didn’t know that I should use include guards in headers. Always refer to a module through its header. I didn’t know template and inline function definitions must appear in the header file. I didn’t know that we should keep a modules internal declarations out of the header file. I didn’t know to put declarations in the narrowest scope possible in the header file. I didn’t know that where possible use an incomplete declaration. Include the forwarded libraries instead of the normal libraries whenever possible. I didn’t know that a .cpp file should include its header first. I didn’t know static initialization happens before the program starts. I didn’t know that we don’t even need an object to use the static member variable. I didn’t know you can access a private static member variable outside of the class if you are initializing it. I didn’t know you can’t access non-static member variables (unless passed as parameters) from a static member function. I didn’t know the source of a move is not required to have its original value. I didn’t know that the special member functions discussed can be generated by the compiler. I didn’t know the name of the class can’t be a member function or variable besides a constructor. I didn’t know we can prevent the destruction of an object by declaring its destructor =delete or private. Declaring private allows us to remove implicit destruction, but still gives us an option for defining explicit destruction. I didn’t know we cannot define a constructor for a built-in type. I didn’t know the default initialization of using {} is defined as initialization of each member by {}. I didn’t know that if we leave out an initializer only statically allocated objects work the same as default initializer and that local objects only initialize members of a class type. I didn’t know memberwise initialization only works if we can access the members. I didn’t know that if a constructor is declared for a class, some constructor will be used for every object. I didn’t know that you can specifically disallow copying. I didn’t know that {} initialization is sometimes referred to as universal initialization. I didn’t know the default constructor is not invoked for non-static built-in local variables. I didn’t know that the constructors are called in order in which the members are declared in the class rather than their order in the initializer list. I didn’t know member destructors are called in reverse order of construction after the body of the class’s own destructor has been executed. I didn’t know there is an efficiency advantage to using the initializer syntax. I didn’t know a constructor can call another constructor of the same name in an initializer. I didn’t know that you cannot both delegate and initialize a member. I didn’t know that an object is considered constructed when the delegated constructor completes. So can we not declare static data members in-class? I didn’t know that if a member is initialized in-class and in a constructor the constructor’s initialization is done. I didn’t know that declare a static member in-class it must be a const integral or enumeration, or a constexpr of a literal type, and the initializer must be a constant-expression. I didn’t know that after a move we must leave the source object in a valid state. I didn’t know that moves don’t throw. I didn’t know that the copy constructor initializes uninitialized memory where the copy assignment must handle an object that has already been constructed. Always remember to copy every base and member. I didn’t know that copy operations should maintain independence. I didn’t know that copies that violate independence are called shallow copies. I didn’t know that an immutable shared state is not a problem. I didn’t know that copy-on-write is a programming technique. I didn’t know the idea behind a move assignment is to handle lvalues separately from rvalues. I didn’t know that if we try to swap objects that do not have a move constructor we actually copy. I didn’t know that if a programmer defines one or more of the “special operations” then generation of related operations is suppressed. I didn’t know we can explicitly state a “special operation” as the compilers default. I didn’t know that sometimes it is a good thing to suppress the compiler generated operations. I didn’t know we can set a function equal to delte to make it an error to try to use it explicitly or implicitly. I didn’t know we can use delete to get rid of an unwanted conversion, or to control where a class can be allocated.
I didn’t know that you can’t overload an operator that only applies to built-in types. I didn’t know that a non-member operator overload function is really just an ordinary function with the name of the operation. I didn’t know calling the operator function is legal. I didn’t know a member operator overload can only be applied if the lhs or this is the class type. I didn’t know that the << overloaded operator can not be a member of your own class. I didn’t know we return the os by reference so we can cascade the << operator. It seems useful to have an overloaded input operator if we can assume the input is nice. Can we call a unary operator overload as a function? I didn’t know we need different syntax for overloading prefix and postfix operators. I didn’t know we can define a conversion operator for user types. I didn’t know the compiler can use a constructor to convert types. I didn’t know we can use the explicit keyword to prevent this. If a pointer is a built-in type how did they overload the operators for the smart pointers? I didn’t know that a function call operator must always be a member function of the class. I didn’t know the scope resolution, member selection, and member selection through pointer to member cannot be defined by a user. I didn’t know that it is not possible to define new operator tokens. I didn’t know an operator can be declared only for the syntax defined for it in the grammar. Why can’t operator overloads be static? I didn’t know that delete also works on operators. I didn’t know we can define operators for enums. Why is it almost always faster to access an argument passed by value than one passed by reference. I didn’t know that operators defined in namespaces can be found based on their operand types just as functions can be, which makes a lot of sense. I didn’t know that in operator lookup no preference is given to members over nonmembers, something that differs from named functions. I didn’t know we can define non-member operators in terms of member operators. I didn’t know to define the same operator to take in different types is called mixed-mode arithmetic. I didn’t know we can use conversion to avoid writing multiple operators to account for mixed-mode arithmetic. I didn’t know we can define a user-defined literal. So accessor functions don’t compromise performance? I didn’t know a constructor cannot specify an implicit conversion to a built-in type or a conversion from a new class to a previously defined class. I didn’t know if it is possible to get ambiguities between user-defined operators and built-in operators. I didn’t know it is possible to declare a conversion operator explicit. I didn’t know only one level of user-defined implicit conversion is legal. I didn’t know user-defined conversions are considered only if a call cannot be resolved without them. I didn’t know that a function call can be interpreted as a binary expression. I didn’t know the call operator is also known as the application operator. I didn’t know function call operators are often templates. I didn’t know that for user-defined operators there is no guarantee -> and * will behave the same way as the normal pointers. I didn’t know that the -> operator overload must return a pointer or an object of a class to which you can apply the ->. Is there no way to have one overloaded operator to deal with both prefix and postfix. Is the postfix operator for built-in types less efficient than the prefix? I didn’t know a new expression may ask for more memory than is indicated by N*sizeof(X). I didn’t know you can replace the global new and delete operators. I didn’t know member new and delete operators are implicitly static members. Why is this? I didn’t know we can avoid storing size information with each allocation. I didn’t know it is not possible to redefine the meaning of built-in literals or to augment the syntax of literals. So we can’t have a literal that is user-defined and then suffixed? I didn’t know that we can have a template literal operator. I didn’t know the standard library reserves all suffixes not starting with an initial underscore. I didn’t know a range check can increase overhead. I didn’t know we can have different representations of our user-defined objects to make them more efficient, such as the short string optimization. I didn’t know that anonymous unions are specifically designed to allow a class to manage alternative representations of objects. What exactly is an ancillary function? I didn’t know that we can declare functions as friends. I didn’t know a friend declaration can be placed in either the private or public part of a class definition. I didn’t know it is possible to make a template argument a friend. I didn’t know scopes outside the innermost enclosing namespace scope are not considered for a name first declared as friend. I didn’t know a friend function can be found by having it take an argument of its class or a derived class. I didn’t know binary operators are the most common source of friend functions. I didn’t know templates can match handwritten, less general code in run-time and space efficiency. I didn’t know templates are type-safe. I didn’t know we can alternatively write template. I didn’t know the name of a class template is followed by the angled brackets. I didn’t know string is a synonym for basic_string. I didn’t know that unless otherwise stated the rules for templates apply equally to class templates and function templates. I didn’t know that when a member is defined outside its class, it must explicitly be declared a template. I didn’t know we can use specialization to provide alternative implementations for a template given specific template arguments. I didn’t know a version of a template for a specific template argument list is called specialization. So templates actually generate code when things like constructors and destructors are needed? I didn’t know that if used incautiously templates can generate very similar large functions and can cause code bloat. I didn’t know there is no way to directly express requirements on a template argument. I didn’t know that the checking of template argument requirements (concepts) is actually done, but it is done too late in the compilation process. I didn’t know that types generated from a single template by different template arguments are different types, even for types from related arguments. I also didn’t know that conversions between generated classes can be defined. I didn’t know errors that relate to the use of template parameters cannot be detected until the template is used. I didn’t know that this is called the first point of instantiation. Why can’t non-static data members be constexpr if they can be initialized in its definition. Can we have constexpr member functions? I didn’t know a virtual member function cannot also be a member function template. I didn’t know the template argument names are only accessible to the template itself. I didn’t know the out-of-class definition of a member enumeration is only allowed for an enumeration for which we know the underlying type. I didn’t know a template constructor is never used to generate a copy constructor. I didn’t know a member template cannot be virtual. I didn’t know so many problems arose in template nesting. I didn’t know that the <> after the name of a friend function is needed to make clear that it is a template function. I didn’t know that if you introduce a new class you in a friend declaration it is legal. I didn’t know there is no way of saying x should only be a friend of y. I didn’t know there are so many ways for a compiler to deduce a template argument. I didn’t know that if a template parameter can be deduced from more than one function argument the same type must be the result of each deduction. I didn’t know we can overload function templates. I didn’t know we can resolve ambiguities by explicit qualification. I didn’t know substitution failure is not an error. I didn’t know there is notation for explicit specialization. I didn’t know that in general if we bind all arguments of a template we get a type. I didn’t know it is up to the compiler to generate code when needed and to optimize the process of reading redundant definitions.
I didn’t know the base class is also known as the superclass and the derived classes are known as subclasses. I didn’t know interface inheritance is often referred to as run-time polymorphism. I didn’t know there is no memory overhead by deriving a class. I didn’t know we can explicitly convert a Base* to Derived*. I didn’t know a derived class cannot access the private members of a base class. I didn’t know c++ can express a directed acyclic graph of classes. I can see why the type-field solution is not recommended. I didn’t know a virtual member function is sometimes called a method. I didn’t know a virtual member function must be defined for the class in which it is first declared, unless it is a pure virtual member function. I didn’t know a virtual function can be used even if there is no class derived from its class. I didn’t know a type with virtual functions is called a polymorphic type or more specifically a run-time polymorphic type. I didn’t know a function that overrides a virtual function itself becomes virtual, and we do not have to repeat the virtual in the derived class. I didn’t know the compiler uses virtual function tables to keep track of which function to call. I didn’t know calling a function using the scope resolution operator ensures the virtual mechanism is not used. I didn’t know final meant the function is not meant to be overridden. I didn’t know we should use override on all functions intended as overriders. I didn’t know override cannot be repeated in an out-of-class definition. I didn’t know override can be used as an identifier elsewhere. I didn’t know we want to use final when we want to close out design to modification from its users. I didn’t know we can make every virtual member function of a class final by putting final after the class name. I didn’t know using declarations can be used to add a function to a scope. Why can’t we use using declarations to bring all members of a base class into a derived class? I didn’t know we can use the using declarations to add a construct to a scope. I didn’t know that if the original return type was B* the return type of the overriding function in a derived class may be D* and this is known as the covariant return rule. I didn’t know constructors interact with memory management routines in ways ordinary member functions don’t. I didn’t know a class with one or more pure virtual functions is an abstract class, and no objects of that abstract class can be created. I didn’t know a class that does not define an inherited pure virtual function is also an abstract class. I didn’t know a compiler may reorder sections of a class with separate access specifiers. I didn’t know a derived class can access a base class’s protected members only for objects of its own type. I didn’t know we can specify access specifier at the class declaration. I didn’t know if the name of a base class can be reached through multiple paths, it is accessible if it is accessible through any path.
I didn’t know virtual function calls also isolate the user from changes in the implementations of the derived classes. Is a pure interface a class with all pure virtual functions? I didn’t know implementation aids that you also want to be accessible to derived classes are supposed to be derived using protected. I didn’t know deriving from more than one class is called multiple inheritance. I didn’t know we can make an abstract class to represent the set of creation operations. I didn’t know that such a class is called a factory and its functions are sometimes called virtual constructors. I didn’t know any class without mutable state can be used as an interface in a multiple-inheritance lattice without significant complications and overhead. I didn’t know we can disambiguate functions by qualifying a member name by its class. I didn’t know a qualified name can either refer to a function in the derived class or one of its base classes. I didn’t know we can add an interface layer to disambiguate the unlikely case where two base classes provide operations with exactly the same name, but with different semantics. I didn’t know we can avoid replication of a base class by declaring a base class virtual and that every virtual base of a derived class is represented by the same shared object. Is this kind of like a static instance of a class? I didn’t know we can expect a storage overhead of one word for each virtual base. I didn’t know that a constructor of a virtual base is constructed exactly once. I didn’t know knowledge of a virtual base and the obligation to initialize it “bubbles up” to the most derived class.
I didn’t know a class lattice is often called a class hierarchy. I didn’t know objects passed back and forth between the system and the application are commonly referred to as widgets or controls. I didn’t know that dynamic cast can be used for run-time type identification. I didn’t know run-time type identification is often abbreviated as RTTI. I didn’t know a cast that goes from a base to a sibling class is called a crosscast. I didn’t know dynamic cast doesn’t allow the accidental violation of the protection of private and protected base classes. I didn’t know a dynamic cast used as an upcast implies no overhead. I didn’t know there is a requirement that the conversion must be to a uniquely identified object. I didn’t know dynamic cast requires a pointer or reference to a polymorphic type in order to do a downcast or crosscast. I didn’t know an implementation might attach a “type information object” to an object by placing a pointer to the type information in the virtual function table for the object’s class. I didn’t know that the overhead involved is just a few comparisons to the type information. I didn’t know we can wrap a concrete type in a polymorphic type and then unwrap the concrete type later. I didn’t know dynamic cast to void* can be used to determine the beginning of an object of polymorphic type. I didn’t know if the operand of a dynamic cast to a reference isn’t of the expected type, a bad_cast exception is thrown. I didn’t know kinds or run-time ambiguity detection is only needed for virtual bases. It makes sense that a dynamic cast cannot cast from a void*. I didn’t know there is a typeid operator that returns a reference to the type_info. I didn’t know we can use type_ids as keys for ordered containers.
I didn’t know some facilities are provided by the standard library because it is conventional and useful to do so. I didn’t know one of the roles the standard library was determined by was to be a set of components enabling intra-library communications. I didn’t know a standard header starting with the letter c is equivalent to a header in the c standard library. I didn’t know a bitset was an array of bool. I didn’t know manipulators are objects used to manipulate the state of a stream. I didn’t know the standard library has the locale to represent cultural differences that some programmers may need. I didn’t know some implementations optimize compilation based on standard header inclusion. I didn’t know range-for is mapped to a for-statement using an iterator. I didn’t know that we shouldn’t throw built-in types. I didn’t know that not all exceptions are part of the standard-library exception hierarchy. I didn’t know the error message produced by assert() is implementation-defined. I didn’t know associative containers lookup based on keys. I didn’t know something like a container adapter existed where we can get specialized access to underlying containers. Why would we use an almost container? I didn’t know a deque was a mixture of linked-list and contiguous allocation. I didn’t know elements of an associative container do not move when elements are inserted or deleted. What is linked overflow? I didn’t know the equality function is used to decide whether two objects with the same hash code are equal. I didn’t know that a string is an almost container. I didn’t know that if a type has a copy or move the standard-library swap() will work. I didn’t know that ordering criterion must define strict weak ordering. I didn’t know < on C-style strings compares pointer values. I didn’t know that when you supply a comparison, equality is tested using two comparison. I didn’t know that if equals always gives the same result as the equivalence test we have total order. I didn’t know the size() operation is constant for all operations. I didn’t know that assignment does not copy or move allocators. I didn’t know there is a max_size() function. I didn’t know that performance is rarely a good reason to use reserve(). I didn’t know there are so many different kinds of iterators. I didn’t know the emplace() operation is used when it is potentially inefficient to first create an object and then copy (or move) it into a container. I didn’t know c1<=c2 is the same as !(c2<c1). I didn’t know the standard does not specify how much capacity is increased when it is exceeded. I didn’t know that iterators become invalidated when reallocation happens. I didn’t know the sizeof(vector) is only about 12 bytes. I didn’t know that a multi-dimensional vector can have more overhead than a specific multi-dimensional type. I didn’t know a splice() operation does not copy element values and does not invalidate iterators to elements. I didn’t know some list operations are stable. I didn’t know sets are maps without values. I didn’t know if you try to insert a value into a map that already is an element with its key, the map is unchanged. I didn’t know we cannot change the values of a set. I didn’t know iteration over an unordered_map depends on the order of insertion, the hash function, and the load factor. I didn’t know you could specify the number of buckets when making an unordered_map. I didn’t know the load factor of an unordered_associative container is the fraction of the capacity that has been used. I didn’t know we can set the max_load_factor. I didn’t know a stack can underflow. What does it mean for a stack to underflow? I didn’t know the order in which elements with equal priority come to the head of the priority queue is not defined. How do the creators of the STL decide to put a container in the STL? I didn’t know an array can be allocated with its elements on the stack, in an object, or in static storage. I didn’t know that there is no overhead involved in using an array compared to using a built-in array. I didn’t know no management information is stored in an array. I didn’t know the number of elements and subscript values for array are of an unsigned type (size_t). I didn’t know that if necessary an array can be passed to a C-style function that expects a pointer. I didn’t know that there can be a performance advantage to accessing elements on the stack. I didn’t know an operation on pair is noexcept if the corresponding operations on its elements are. I didn’t know we can assign tuple to another if each element of the assigned tuple can be assigned to the target element. I didn’t know a tuple operation is constexpr if the element operations are. I didn’t know the name ignore refers to an object of a type that ignores assignments.
I didn’t know the stl functions for character classification are most likely faster than handwritten code. I didn’t know the members of the standard char_traits are all static functions. I didn’t know strlen() is an O(n) operation. I didn’t know string::npos represents a position beyond a string’s length. I didn’t know there is no implicit conversion from string to a char*. I didn’t know we can specify the base in stoi(). I didn’t know the find functions use string::npos. I didn’t know an ostream converts typed objects to a stream of characters and an istream converts a stream of characters into typed objects. I didn’t know that no copy operations are provided for streams. I didn’t know there are eight standard streams. I didn’t know there is a member for the position in a file. I didn’t know you can open a file in different modes. When would we use a stringstream? I’m confused about what a sentry is. I didn’t know that if a pointer to a function is the target of >>, that function will be invoked with the istream as its argument. I didn’t know skipping of whitespace can be suppressed using noskipws. I didn’t know the STL has so many unformatted input operations. I didn’t know the STL has operations on the streambuf. I didn’t know virtual functions are used to achieve flexibility for the operations dealing with buffer overflow and underflow only. I didn’t know you can integrate a virtual function into the framework provided by the ostream and <<. I didn’t know a manipulator was a pointer to a function given as the second argument to <<. I didn’t know the ios_base has member bitmask types. I didn’t know there are so many formatting constants in the ios_base. I didn’t know the format state can be read and written by operations. I didn’t know that precision() is “sticky”. I didn’t know the default fill character is the space character. I didn’t know that the floating-point format is “sticky”. I didn’t know we can make user-defined manipulators.
I didn’t know some of the STL algorithms only need a single iterator for outputs. Are there any overhead advantages to using different kinds of iterators. I didn’t know that whatever an STL algorithm returns it cannot be an argument container. I didn’t know the _if suffix is often used to indicate the algorithm takes a predicate. I didn’t know that we shouldn’t try to modify elements through predicates, or that a predicate should not carry a state that changes the meaning of its operation. I didn’t know traversing a list can be much slower than traversing a vector even though they have the same complexity. How is for_each() a non-modifying algorithm? I didn’t know when one of the sequence predicates fais, it does not tell which elements caused the failure. I didn’t know the find_first_of() compares two containers. I didn’t know the search() and search_n() find one sequence as a subsequence in another. I didn’t know modifying algorithms are also called mutating sequence algorithms. I didn’t know the target of a copy algorithm need not be a container. I didn’t know we can use inserters to grow the target as needed in an STL function call. I didn’t know unique() doesn’t eliminate duplicates in a vector, but rather moves them to the front and returns and iterator to the end of the subsequence of unique elements. I didn’t know remove does not actually remove elements from the container, but rather moves them to the end. I didn’t know the STL provides systematic ways of moving elements around in a sequence or a way to permute elements in a sequence. I didn’t know elements that are targets of uninitialized_fill() or uninitialized_copy() must be built-in types or uninitialized. I didn’t know the STL provided variants of sort(). I didn’t know we cannot sort directly to cout. I didn’t know algorithms are provided for finding a range of equal elements. Why would we use merge instead of inplace_merge? I didn’t know the heap allows a programmer to treat a random-access sequence as a heap. So lexigraphical compare is used on containers that are not necessarily strings? I didn’t know that if in the STL comparison functions if we compare two lvalues the result if a reference to the result and otherwise an rvalue is returned. I didn’t know a sequence is defined by a pair of iterators defining a half-open range. I didn’t know only random-access iterators support <. I didn’t know there are five kinds of iterators and that they can have different properties. I didn’t know for more complicated iterators ++p is likely to be more efficient than p++. I didn’t know reverse iterators are iterator adapters. Why would we use reverse iterators instead of just traversing backwards? I didn’t know inserters are insert iterators. I didn’t know there are three insert iterators. I didn’t know there are move iterators and that move iterators are basically what the move() algorithm does internally. I didn’t know a function adapter takes a function as an argument and returns a function object that can be used to invoke the original function. I didn’t know we don’t have to bind every argument of a function when using bind(). I didn’t know the function adapter mem_fn(mf) produced a function object that can be called as a nonmember function. I didn’t know we can assign the result of a bind() to the STL type function. It makes sense that an object of type function is a function object. I didn’t know the operators provided for stream iterators are the same as for other iterator adapters. I didn’t know that something like a pointer to member exists. I didn’t know a null pointer can be assigned to a pointer to member and then represents no member. I didn’t know a pointer to member can be obtained by applying the address-of operator to a fully qualified class member name. I didn’t know a pointer to a member isn’t a pointer to a piece of memory the way a pointer to a variable or function is, but a pointer to a static member is an ordinary pointer. I didn’t know 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. This is known as contravariance. I didn’t know the same type lookup approach is known as homogeneous lookup. I didn’t know we can use a probe of a different type than the container objects and that this is known as heterogeneous lookup. I didn’t know that in some cases we do not need a probe object. I didn’t know the vector push sort method was so slow and that the maps are so efficient. I didn’t think about lambdas in the conceptual manner where we might want to use them in places where we don’t want to declare a full-fledged function to a status it does not deserve. I didn’t know you can call a lambda in the same statement that creates it. I didn’t know that for lambdas if there is no return statement in the function body the return type is automatically void. I didn’t know we can specify the return type of a lambda. I didn’t know captured variables in a lambda are actually member variables that hold a copy of the values of the variables in the outer scope. I didn’t know a lambda object that holds captured values is known as a closure. I didn’t know we have to use the this pointer if we want to use lambdas inside member functions that change member variables. I didn’t know [this] and [=] are incompatible. I didn’t know a common use for bind is to create function objects to use in STL algorithms. I didn’t know the bound arguments are stored as member variables. I didn’t know there is a reference wrapper call that produces the effect of a copyable reference. I didn’t know the position of the placeholder in the bound argument list corresponds to the same position in the function argument list. I didn’t know the call argument list can have extra values that do not need to be used. I didn’t know we can use expressions and functions as call arguments in bind. I didn’t know you can nest binds. I didn’t know the inner binds are evaluated before the outer binds.
I didn’t know that you a unique_ptr has a pair of pointers if it has a deleter. Where the deleter represents what it means to delete an object. It makes sense that unique_ptr does not offer copy assignment or copy construction. I didn’t know it is possible to have a unique_ptr for a built-in array and that this is provided as a specialization. I didn’t know that this specialization is not provided for class hierarchies to avoid slicing. I didn’t know that with shared_ptrs there can be a significant “garbage collection delay”. I didn’t know that we should minimize the use of weak_ptrs. I didn’t know garbage collection is optional. I didn’t know that we should prefer smart pointers to garbage collection.