5.5.1
One important way in which the operations on lists differ from those on vectors is the effect of some of the operations on iterators. For example, when we erase an element from a vector, all iterators that refer to the element erased, or subsequent elements, are invalidated. Using push_back to append an element to a vector invalidates all iterators referring to that vector. This behavior follows from the fact that erasing an element moves the following elements, and appending to a vector might reallocate the entire vector to make room for the new element. Loops that use these operations must be especially careful to ensure that they have not saved copies of any iterators that may be invalidated. Inappropriately saving the value of students.end() is a particularly rich source of bugs.
For lists, on the other hand, the erase and push_back operations do not invalidate iterators to other elements. Only iterators that refer to the element actually erased are invalidated, because that element no longer exists.
6.2.4
The unsigned integer types are ideal for uses that treat storage as a bit array. Using an unsigned instead of an int to gain one more bit to represent positive integers is almost never a good idea. Attempts to ensure that some values are positive by declaring variables unsigned will typically be defeated by the implicit conversion rules
Unlike plain chars, plain ints are always signed.
In addition, it is guaranteed that a char has at least 8 bits, a short at least 16 bits, and a long at least 32 bits
6.3.3
Names
A name (identifier) consists of a sequence of letters and digits. The first character must be a letter.The underscore character, _, is considered a letter.
Do not encode type information in a name (e.g., pcname for a name that’s a char∗ or icount for a count that’s an int) as is sometimes done in languages with dynamic or weak type systems:
Encoding types in names lowers the abstraction level of the program; in particular, it pre- vents generic programming (which relies on a name being able to refer to entities of differ- ent types).
The compiler is better at keeping track of types than you are.
If you want to change the type of a name (e.g., use a std::string to hold the name), you’ll
have to change every use of the name (or the type encoding becomes a lie).
Any system of type abbreviations you can come up with will become overelaborate and
cryptic as the variety of types you use increases. Choosing good names is an art.
6.3.6.1
Note that the type of an expression is never a reference because references are implicitly deref-erenced in expressions (§7.7). For example:
void g(int& v) {
auto x = v; // x is an int (not an int&)
auto& y = v; // y is an int&
}
7.2.1
A pointer to any type of object can be assigned to a variable of type void∗
, but a pointer to function (§12.5) or a pointer to member (§20.6) cannot.
7.3
The number of elements of the array, the array bound, must be a constant expression (§10.4). If you need variable bounds, use a vector (§4.4.1, §31.4). For example:
void f(int n) {
int v1[n]; // error: array size not a constant expression
vector<int> v2(n); // OK: vector with n int elements
}
Often, a char∗
or a const char∗
is assumed to point to a zero-terminated sequence of characters.
7.3.2
A string literal is statically allocated so that it is safe to return one from a function. For example:
const char∗ error_message(int i) {
// ...
return "range error";
}
The memory holding "range error" will not go away after a call of error_message().
7.5
The declarator operator that makes a pointer constant is ∗const
. There is no const∗
declarator operator, so a const appearing before the ∗ is taken to be part of the base type. For example:
char ∗const cp; // const pointer to char
char const∗ pc; // pointer to const char
const char∗ pc2; // pointer to const char
网友评论