将书中每章的 Details 部分摘录过来,方便自己之后重翻。并在之后的使用中,添加一些注释。因为有些还不知道怎么熟练使用。
TODO 给 code-snippets 目录下的代码添加测试代码
Program Structure: C++ programs are usually in free form , meaning that spaces are required only when they keep adjacent symbols from running together. In particular, newlines are just another kind of space, and usually have no additional special meaning. Where you choose to put spaces in a program can make it much easier or harder to read. Programs are normally indented to improve readability.
There are three entities that are not free-form:
string literals
characters enclosed in double quotes; may not span lines#include name
must appear on a line by themselves (except for comments)
In C++, many fundamental facilities, such as input-output, are part of thestandard library
, rather than being part of thecore language
. This distinction is important because the core language is always available to all C++ programs, but you must explicitly ask for the parts of the standard library that you wish to use.来自 C++ Primer 推荐序3
什么是一门语言的核心部分呢?就是指一门语言不需要任何库(包括标准库)支持的那部分。只要是一个符合标准的 C++ 语言的编译器,无论运行在什么硬件和操作系统上,只要程序员使用的是 C++ 语言,就应该可以使用的那部分语言特性。比如,基本类型和量化饰词、基本语句如
if
和for
、函数声明语法、外部连接指示等,这些就属于语言核心。而像 STL 提供的标准容器如vector
和map
、标准算法如find
和sort
等就不属于语言核心。// comments
// followed by anything,; ends at the end of the current line. A comment that begins with/*
is free-form; it ends with the first subsequent*/
and can span multiple lines.
Types define data structures and operations on those data structures. C++ has two kinds of types: those built into the core language, such as int
, and those that are defined outside the core language, such as std::ostream
.
Namespaces are mechanism for grouping related names. Names from the standard library are defined in the namespace called std
.
String literals begin and end with double quotes ( "
); each string literal must appear entirely on one line of the program. Some characters in string literals have special meaning when preceded by a backslash ( \
):
\n
newline character\t
tab character\b
backspace character\"
treats this symbol as part of the string rather than as the string terminator\'
same meaning as'
in string literals, for consitency with character literals\\
includes a\
in the string, treating the next character as an ordinary character
Definitions and headers: Every name that a C++ program uses must have a corresponding definition. The standard library defines its names in headers, which programs access through #include
. Names must be defined before they are used; hence, a #include
must precede the use of any name from that header. The <iostream>
header defines the library’s input-output facilities.
The main function: Every C++ program must define exactly one function, named main
, that returns an int
. The implementation runs the program by calling main
. A zero return from main
indicates success; a nonzero return indicates failure. In general, functions must include at least one return
statement and are not permitted to fall off the end of the function. The main
function is special: It may omit the return; if it does so, the implementation will assume a zero return value. However, explicitly including a return from main
is good practice.
Braces and semicolons: These inconspicuous symbols are important in C++ programs. They are easy to overlook because they are small, and they are important because forgetting one typically evokes compiler diagnostic messages that may be hard to understand.
A sequence of zero or more statements enclosed in braces is a statement, called a block , which is a request to execute the constituent statements in the order in which they appear. The body of a function must be enclosed in braces, even if it is only a single statement. The statements between a pair of matching braces constitute a scope
.
An expression followed by a semicolon is a statement, called an expression statement , which is a request to execute the expression for its side effects and discard its result. The expression is optional; omitting it results in a null statement , which has no effect.
Output: Evaluating std::cout << e
writes the valued e
on the standard-output stream, and yields std::cout
, which has type ostream
, as its value in order to allow chained output operations.
Types:
char
Built-in type that holds ordinary characters as defined by the implementation.wchar_t
Built-in type intended to hold “wide characters”, which are big enough to hold characters for languages such as Japanese.
The string type is define in the standard header <string>
. An object of type string
contains a sequence of zero or more characters. If n
is an integer, c
is a char
, is
is an input stream, and os
is an output stream, then the string
operations include:
std::string s;
Definess
as a variable of typestd::string
that is initially empty.std::string t = s;
Definest
as a variable of typestd::string
that initially contains a copy of the characters ins
, wheres
can be either astring
or a string literal.std::string z(n, c);
Definesz
as a variable of typestd::string
that initially containsn
copies of the characterc
. Here,c
must be achar
, not astring
or a string literal.os << s
Writes the characters contained ins
, without any formatting changes, on hte output stream denoted byos
. The result of the expression isos
.is >> s
Reads and discards characters from the stream denoted byis
until encountering a character that is not whitespace. Then reads successive characters fromis
intos
, overwriting whatever values
have had, until the next character read would be whitespace. The result isis
.s + t
The result of this expression is anstd::string
that contains a copy of the characters ins
followed by a copy of the characters int
. Eithers
ort
, but not both, may be a string literal or a value of typechar
.s.size()
The number of characters ins
.
Variables can be defined in one of three ways:
std::string hello = "Hello"; // define the variable with an explicit initially
std::string stars(100, '*'); // construct the variable according to its type and the given expression
std::string name; // define the variable with an implicit initialion which depends on its type
Variables defined inside a pair of curly braces are local variables, which exist only while executing the part of the program within the braces. When the implementation reaches the }
, it destroys the variables, and returns any memory that they occupied to the system. Defining a variable as const
promises that the variable’s value, will not change during its lifetime. Such a variable must be initialized as part of its definition, because there is no way to do so later.
Input: Executing std::cin >> v
discards any whitespace characters in the standard input stream, then reads from the standard input into variable v
. It returns std::cin
, which has type istream
, in order to allow chained input operations.
Expressions: C++ inherits a rich set of operators from C, several of which we have already used. In addition, as we’ve already seen with the input and output operators, C++ programs can extend the core language by defining what it means to apply built-in operators to objects of class type. Correctly understanding complicated expressions is a fundamental prerequisite to effective programming in C++. Understanding such expressions requires understanding:
- How the operands groups, which is controlled by the precedence and associativity of the operators used in the expression
- How the operands will be converted to other types, if at all
- The order in which the operands are evaluated
Different operators have different precedence. Most of the operators are left-associative, although the assignment operators and the operators taking a single argument are right-associative. We list the most common operators here regardless of whether we’ve used them in this chapter. We’ve ordered them by precedence from highest to lowest, with a double line separating groupings with the same precedence.
x.y
The membery
of objectx
x[y]
The element in objectx
indexed byy
x++
Incrementsx
, returning the original value ofx
x--
Decrementsx
, returning the original value ofx
- ++++++++++
++x
Incrementsx
, returning the incremented value--x
Decrementsx
, returning the decremented value!x
Logical negation. Ifx
istrue
then!x
isfalse
- ++++++++++
x * y
Product ofx
andy
x / y
Quotient ofx
andy
. If both operands are integers, the implementation chooses whether to round toward zerox % y
Remainder ofx
divided byy
, equivalent tox - ((x / y) * y)
- ++++++++++
x + y
Sum ofx
andy
x - y
Resulet of subtractingy
fromx
x >> y
For integralx
andy
,x
shifted right byx
bits;y
must be non-negative. Ifx
is anistream
, reads fromx
intoy
x << y
For integralx
andy
,x
shifted left byy
bits;y
must be non-negative. Ifx
is anostream
, writesy
ontox
- ++++++++++
x relop y
Relational operators yield abool
indicating the truth of the relation. The operators (<
,>
,<=
,>=
) have their obvious meanings- ++++++++++
x == y
Yields abool
indicating whetherx
equalsy
x != y
Yields abool
indicating whetherx
is not equal toy
- ++++++++++
x && y
Yields abool
indicating whether bothx
andy
aretrue
. Evaluatesy
only ifx
istrue
- ++++++++++
x || y
Yields abool
indicating whether eitherx
ory
istrue
. Evaluatesy
only ifx
isfalse
- ++++++++++
x = y
Assign the valuey
tox
, yieldingx
as its resultx op= y
Compound assignment operators; equivalent tox = x op y
, whereop
is an arithmetic or shift operator- ++++++++++
x ? y1 : y2
Yieldsy1
ifx
istrue
;y2
otherwise. Evaluates only one oft1
andy2
There is usually no guarantee as to the order in which an expression’s operands are evaluated. Because the order of evaluation is not fixed, it is important to avoid writing a single expression in which one operand depends on the value of another operand.
Operands will be converted to the appropriate type when possible. Numeric operands in expressions or relational expressions are converted by the usual arithmetic conversions . Basically, the usual arithmetic conversions attempt to preserve precision. Smaller types are converted to larger types, and signed types are converted to unsigned. Arithmetic values may be converted to bool
: A value of 0
is considered false
; any other value is true
. Operands of class type are converted as specified by the type.
Types:
bool
Built-in type representing truth values; may be eithertrue
orfalse
unsigned
Integral type that contains only non-negative valuesshort
Integral type that must hold at least 16 bitslong
Integral type that must hold at least 32 bitssize_t
Unsigned integral type (from<cstddef>
) that can hold any object’s sizestring::size_type
Unsigned integral type that can hold the size of anystring
Half-open ranges include one but not both of their endpoints. For example, [1, 3)
includes 1
and 2
, but not 3
.
Condition: An expression that yields a truth value. Arithmetic values used in conditions are converted to bool
: Nonzero values convert to true
; zero values convert to false
.
Statements:
Using namespace-name::name;
Defines name as a synonym fornamespace-name::name
type-name name;
Defines name with typetype-name
type-name name = value;
Defines name with typetype-name
initialized as a copy of valuetype-name name(args);
Defines name with typetype-name
constructed as appropriate for the given arguments inargs
expression;
Executesexpression
for its side effects{ statement(s) }
Called a block. Executes the sequence of zero or morestatement(s)
in order. May be used wherever astatement
is expected. Variables defined inside the braces have scope limited to the blockwhile (condition) { statement(s) }
Ifcondition
isfalse
, do nothing; otherwise, executestatement(s)
and then repeat the entirewhile
for (init-statement; condition; expression) { statement(s) }
Equivalent to{ init-statement while (condition) { statement(s) } }
if (condition) { statement(s) }
Executesstatement(s)
ifcondition
istrue
if (condition) { statement1(s) } else { statement2(s) }
Executesstatement1(s)
ifcondition
istrue
, otherwise executesstatement2(s)
. Eachelse
is associated with the nearest matchingif
return val;
Exit the function and returnsval
to its caller
Local variables are default-initialized if they are defined without an explicit initializer. Default-initialization of a built-in type means that the value is undefined . Undefined values may be used only as the left-hand side of an assignment.
Type definitions: typedef type name;
Defines name
as a synonym for type
The vector type , defined in <vector>
, is a library type that is a container that holds a sequence of values of a specified type, vectors grow dynamically. Some important operations are:
vector<T>::size_type
A type guaranteed to be able to hold the number of elements in the largest possiblevector
v.begin()
Returns a value that denotes the first element inv
v.end()
Returns a value that donotes (one past) the last element inv
vector<T> v;
Creates an empty vector taht can hold elements of typeT
v.push_back(e)
Grows the vector by one element initialized toe
v[i]
Returns the value stored in popsitioni
v.size()
Returns the number of elements inv
Other library facilities
sort(b, e)
Rearranges the elements defined by the range[b, e)
into nondecreasing order. Defined in<algorithm>
max(e1, e2)
Returns the larger of the expressionse1
ande2
;e1
ande2
must have exactly the same type. Defined in<algorithm>
while (cin >> x)
Reads a value of an appropriate type intox
and tests the state of the stream. If teh stream if in an error state, the test fails; otherwise, the test succeeds, and teh body of thewhile
is executeds.precision(n)
Sets the precision of the streams
ton
for future output (or leaves it unchanged ifn
is omitted). Returns the previous precisionsetprecision(n)
Returns a value that, when written on an output streams
, has the effect of callings.precision(n)
. Defined in<iomapip>
streamsize
The type of the value expected bysetprecision
and return byprecision
. Defined in<ios>
Program structure:
#include <system-header>
Angle brackets,< >
, enclose system headers. System headers may or may not be implemented as files#include "user-defined-header-file-name"
User-defined header files areinclude
d by enclosing the name in quotes. Typically, user-defined headers have a suffix of.h
Header files should be guarded against multiple inclusion by wrapping the file in anifndef GUARD_header_name_h
directive. Headers should avoid declaring names that they do not use. In particular, they should not includeusing
-declarations, but instead should prefix standard-library names withstd::
explicitly.
Types:
T&
Denotes a reference to the typeT
. Most commonly used to pass a parameter that a function may change. Arguments to such parameters must be lvalues .const T&
Denotes a reference to the typeT
that may not be used to change the value to which the reference is bound. Usually used to avoid cost of copying a parameter to a function.
Structures: A structure is a type that contains zero or more members. Each object of the structure type contains its own instance of each of its members. Every structure must have a corresponding definition:
struct type-name {
type-specifier member-name;
...
}; // note the semicolon
Like all definitions, a structure definition may appear only once per source file, so it should normally appear in a properly guarded header file.
Functions: A function must be declared in every source file that uses it, and defined only once. The declarations and definitions have similar forms:
ret-type function-name(parm-decls); // function declaration
[in-line] ret-type function-name(parm-decls) { // function definition
// function body goes here
}
Here, ret-type
is the type that the function returns, parm-decls
is a comma-separated list of the types for the parameters of the function. Functions must be declared before they are called. Each argument’s type must be compatible with the corresponding parameter. A different syntax is necessary to declare or define functions with sufficiently complicated return types.
Function names may be overloaded: The same function-name
may define multiple functions so long as the functions differ in the number or types of the parameters. The implementation can distinguish between a reference and a const
reference to the same type. Confused
We can optionally qualify a funcion definition with inline
, which asks the compiler to expand calls to the function inline when appropriate, that is, to avoid function-call overhead by replacing each call to the function by a copy of the function body, modified as necessary. To do so, the compiler needs to be able to see the function definition, so inline
s are usually defined in header files, rather than in source files.
Exception handling:
try { // code
Initiates a block that mightthrow
an exception} catch (t) { /* code */ }
Concludes thetry
block and handles exceptions that match the typet
. The code following thecatch
performs whatever action is appropriate to handle the exception reported int
throw e;
Terminates the current function; throws the valuee
back to the caller
Exception classes: The library defines several exception classes whose names suggest the kinds of problems they might be used to report:
logic_error
domain_error
invalid_argument
length_error
out_of_range
runtime_error
range_error
overflow_error
underflow_error
e.what()
Returns a value that reports on what happened to cause the error
Library facilities:
s1 < s2
Comparesstring
ss1
ands2
by applying dictionary orderings.width(n)
Set the width of streams
ton
for the next output operation (or leaves it unchanged ifn
is omitted). The output is padded on the left to the given width. Returns the previous width. The standard output operators use the existing width value and then callwidth(0)
to reset the widthsetw(n)
Returns a value of typestreamsize
that, when written on an ouput streams
, has the effect of callings.width(n)
Containers and iterators: The standard library is designed so that similar operations on different containers have the same interface and the same semantics. The containers we have used so far are all sequential containers. The library also provides associative containers. All the sequential containers and the string
type provide the following operations:
container<T>::iterator
container<T>::const_iterator
The name of the type of the iterator on this containercontainer<T>::size_type
The name of the appropriate type to hold the size of the largest possible instance of this containerc.begin()
c.end()
Iterators referring to the first and (one past) the last element in the containerc.rbegin()
c.rend()
Iterators referring to the last and (one beyond) the first element in the container that grant access to the container’s elements in reverse ordercontainer<T> c;
container<T> c(c2);
Definesc
as a container that is empty or a copy ofc2
if givencontainer<T> c(n);
Definesc
as a container withn
elements that are value-initialized according to the type ofT
. IfT
is a class type, that type will control how to initialize the elements. IfT
is a built-in arithmetic type, then the elements will be initialized to 0container<T> c(n, t);
Definesc
as container withn
elements that are copies oft
container<T> c(b, e);
Creates a container that holds a copy of the elements denoted by iterators in the range[b, e)
c = c2;
Replaces the contents of containerc
with a copy of the containerc2
c.size()
Returns the number of elements inc
as asize_type
c.empty()
Predicate that indicates whetherc
has no elementsc.insert(d, b, e)
Copies elements denoted by iterators in range[b, e)
and inserts them intoc
immediately befored
c.erase(it)
c.erase(b, e)
Removes the element denoted byit
or the range of elements denoted by[b, e)
from the containerc
. This operation is fast forlist
but can be slow forvector
andstring
, because for these types it involves copying all the elements after the one that is removed. Forlist
, iterators to the element(s) that are erased are invalidated. Forvector
andstring
, all iterators to elements after the one eraed are invalidatedc.push_back(t)
Adds an element to the end ofc
with the valuet
c[n]
Containers that support random access, and thestring
type, also provide this operation. Fetches the character at positionn
from the containerc
Iterator operations:
*it
Dereferences the iteratorit
to obtain the value stored in the container at the position thatit
denotes. This operation is often combined with.
to obtain a member of a class object, as in(*it).x
, which yields the memberx
of the object denoted by the iteratorit
.*
has lower precedence than.
and the smae precedence as++
and-
it->x
Equivalent to(*it).x
, which returns the memberx
denoted by the object obtained by dereferencing the iteratorit
. Same prededence as the.
operator++it
it++
Increments the iterator so that it denotes the next element in the containerb == e
b != e
Compares two iterator for equality or inequality
The string type offers iterators that support the same operations as do iterators on vector
s. In particular, string
supports full random access. In addition to the operations on containers, string
also provides:
s.substr(i, j)
Creates a newstring
that holds a copy of teh characters ins
with indices in the range[i, i+j)
getline(is, s)
Reads a line of input fromis
and stores it ins
s += s2
Replaces the value ofs
bys + s2
The vector type offers the most powerful iterators, called random-access iterators, of any of the library containers.
Although all the functions we’ve written have relied on dynamically allocating our vector
elements, there are also mechanisms for preallocating elements, and an operation to direct the vector
to allocate, but not to use, additional memory in order to avoid the overhead of repeated memory allocations.
v.reserve(n)
Reserves space to holdn
elements, but does not initialize them. This operation does not change the size of the container. It affects only the frequency with which vector may have to allocate memory in response to repeated call toinsert
orpush_back
v.resize(n)
Givenv
a new size equal ton
. Ifn
is smaller than the current size ofv
, elements beyondn
are removed from thevector
. Ifn
is greater than the current size, then new elements are added tov
and initialized as appropriate to the type inv
The list type is optimized for efficiently inserting and deleting elements at any point in the container. The operations on list
s and list iterators include those described above. In addition,
l.sort()
l.sort(cmp)
Sorts the elements inl
using the<
operator for the type in thelist
, or the predicatecmp
The <cctype> header provides useful functions for manipulating character data:
isspace(c)
true
ifc
is a whitespace characterisalpha(c)
true
ifc
is an alphabetic characterisdigit(c)
true
ifc
is a digit characterisalnum(c)
true
ifc
is a letter or a digitispunct(c)
true
ifc
is a punctuation characterisupper(c)
true
ifc
is an uppercase letterislower(c)
true
ifc
is a lowercase lettertoupper(c)
Yields the uppercase equivalent toc
tolower(c)
Yields the lowercase equivalent toc
Type modifiers:
static type variable;
For local declarations, declares variable with static
storage class. The value of variable persists across executions of this scope and is guaranteed to be initialized before the variable is used for the first time. When the program exits from the scope, the variable keeps its value until the next time the program enters that scope.
Type: The built-in type void
can be used in a restricted number of ways, one of which is to indicate that a function yields no return value. Such functions can be exited through a return
; that has no value or by falling off the end of the function.
Iterator adaptors are functions that yields iterators. The most common are the adaptors that generate insert_iterators
, which are iterators that grow the associated container dynamically. Such iterators can be used safely as the destination of a copying algorithm. They are defined in header <iterator>
:
back_inserter(c)
Yields an iterator on the containerc
that appends elementsc
. The container must supportpush_back
, which thelist
,vector
, and thestring
types all dofront_inserter(c)
Likeback_inserter
, but inserts at the front of the container. The container must supportpush_front
, whichlist
does, butstring
andvector
do notinserter(c, it)
Likebake_inserter
, but inserts elements before the iteratorit
Algorithms: Unless otherwise indicated, <algorithm>
defines these algorithms:
accumulate(b, e, t)
Creates a local variable and initializes it to a copy oft
(with the same type ast
, which means that the type oft
is crucially important to the behavior ofaccumulate
), adds each element in the range[b, e)
to the variable, and returns a copy of the variable as its result. Defined in<numeric>
find(b, e, t)
find_if(b, e, p)
search(b, e, b2, e2)
Algorithms to look for a given value in the sequence[b, e)
. Thefind
algorithm looks for the valuet
; thefind_if
algorithm tests each element against the predicatep
; thesearch
algorithm looks for the sequence denote by[b2, e2)
copy(b, e, d)
remove_copy(b, e, d, t)
remove_copy_if(b, e, d, p)
Algorithms to copy the sequence from[b, e)
to the destination denoted byd
. Thecopy
algorithm copies the entire sequence;remove_copy
copies all elements not equal tot
; andremove_copy_if
copies all elements for which the predicatep
failsremove_if(b, e, p)
Arranges the container so that the elements in the range[b, e)
for which the predicatep
is false are at the front of the range. Returns an iterator denoting one past the range of these “unremoved” elementsremove(b, e, t)
Likeremove_if
, but tests which elements to keep against the valuet
transform(b, e, d, f)
Runs the functionsf
on the elements in the range[b, e)
, storing the result off
ind
partition(b, e, p)
stable_partition(b, e, p)
Partitions the elements in range[b, e)
, based on the predicatep
, so that elements for which the predicate istrue
are at the front of the container. Returns an iterator to the first element for which the predicate isfalse
, ore
if the predicate istrue
for all elements. Thestable_partition
function maintains the input order among the elements in each partition
The do while statement is similar to the while
statement, except that the test is at the end. The general form of the statement is
do {
statement(s)
} while (condition);
The statement(s)
is executed first, after which the condition
and statement(s)
are executed alternately until the condition
is false
Value-initialization: Accessing a map
element that doesn’t yet exist creates an element with a value of V()
, where V
is the type of the values stored in the map
. Such an expression is said to be value-initialized. The most important aspect of value-initialized is that built-in types are initialized to 0
rand() is a function that yields a random integer in the range [0, RAND_MAX]
. Both rand
and RAND_MAX
are defined in <cstdlib>
pair<K, V> is a simple type whose objects hold pairs of values. Access to these data values is through their names, first
and second
respectively
map<K, V> is an associative array with key type K
and value type V
. The elements of a map
are key-value pairs, which are maintained in key order to allow efficient access of elements by key. The iterators on map
s are bidirectional . Dereferencing a map iterator yields a value of type pair<const K, V>
. The map
operations include:
map<K, V> m;
Creates new emptymap
, with keys of typeconst K
and values of typeV
map<K, V> m(cmp);
Creates a new emptymap
with keys of typeconst K
and values of typeV
, that uses the predicatecmp
to determine the order of the elementsm[k]
Indexes themap
using a keyk
of typeK
, and returns an lvalue of typeV
. If there is no entry for the given key, a new value-initialized element is created and inserted into themap
with this key. Becuase using[]
to access amap
might create a new element,[]
is not allowed on aconst map
m.begin()
m.end()
Return iterators that can be used to access the elements of amap
. Note that dereferencing one of these iterators yields a key-value pair, not just a value- m.find(k) Returns an iterator referring to the element with key
k
, orm.end()
if no such element exists
For a map<K, V>
and an associated iterator p
, the following apply:
p->first
Yields an lvalue of typeconst K
that is the key for the elementp
denotesp->second
Yields an lvalue of typeV
that is the value part of the element thatp
denotes