首页 > 代码库 > C++ Primer 读书笔记1

C++ Primer 读书笔记1

1、在Windows系统中输入文件结束符的方法为Ctrl+Z

2、如何选择类型?

1) Use an unsigned type when youknow that the values cannot be negative

2) Use int for integer arithmetic.short is usually too small and, in practice, long often has the same size asint. If your data values are larger than the minimum guaranteed size of an int,then use long long.

3) Do not use plain char or boolin arithmetic expressions. Use them only to hold characters or truth values.Computations using char are especially problematic because char is signed onsome machines and unsigned on others. If you need a tiny integer, explicitlyspecify either signed char or unsigned char.

4) Use double for floating-pointcomputations; float usually does not have enough precision, and the cost ofdouble-precision calculations versus single-precision is negligible. In fact,on some machines, double-precision operations are faster than single. Theprecision offered by long double usually is unnecessary and often entailsconsiderable run-time cost.

signed char c2 = 256;   // assuming 8-bit chars, the value of c2 is undefined

3、If we assign anout-of-range value to an object of signed type, the result is undefined. Theprogram might appear to work, it might crash, or it might produce garbagevalues.

4、Caution: Don’t Mix Signed and Unsigned Types.

5、  ‘a‘  // character literal

 "HelloWorld!"  // string literal

    The type of a string literal is array of constant chars. Thecompiler appends a null character (’\0’) to every string literal. Thus, theactual size of a string literal is one more than its apparent size. Forexample, the literal ‘A‘ represents the single character A, whereas the stringliteral "A" represents an array of two characters, the letter A andthe null character.

// multiline string literal
 std::cout << "a really, really long string literal "             
<span style="white-space:pre">	</span>      "that spans two lines" << std::endl;

6、When you write a long literal,use the uppercase L; the lowercase letter l is too easily mistaken for thedigit 1.

7、The word nullptr is a pointerliteral.

8、Initialization is notassignment. Initialization happens when a variable is given a value when it iscreated. Assignment obliterates an object’s current value and replaces thatvalue with a new one.

9、The generalized use of curlybraces for initialization was introduced as part of the new standard. This formof initialization previously had been allowed only in more restricted ways,this form of initialization is referred to as list initialization.

When used with variables of built-in type, this form ofinitialization has one important property: The compiler will not let us listinitialize variables of built-in type if the initializer might lead to the lossof information:

long double ld = 3.1415926536; 
int a{ld}, b = {ld}; // error: narrowing conversion required 
int c(ld), d = ld;   // ok: but value will be truncated
10、We recommend initializing everyobject of built-in type. It is not always necessary, but it is easier and saferto provide an initializer until you can be certain it is safe to omit theinitializer.

11、A declaration makes a name known to the program. A file that wants touse a name defined elsewhere includes a declaration for that name. Adefinition creates the associatedentity.

extern int i;   // declares but does not define i 
int j;          // declares and defines j
extern double pi = 3.1416; // definition

It is an error to provide an initializer on an externinside a function.

Note: Variables must be defined exactly once but can be declared manytimes.  

12、Warning: It isalmost always a bad idea to define a local variable with the same name as aglobal variable that the function uses or might use.

13、the type of a reference and theobject to which the reference refers must match exactly. Moreover, for reasonswe’ll explore in § 2.4.1, a reference may be bound only to an object, not to aliteral or to the result of a more general expression:

int &refVal4 = 10;   // error: initializer must be an object 
double dval = 3.14; 
int &refVal5 = dval; // error: initializer must be an int object
14、A pointer is a compound type that “points to” another type. Likereferences, pointers are used forindirect access to other objects. Unlike a reference, a pointer is an object inits own right. Pointers can be assigned and copied; a single pointer can pointto several different objects over its lifetime. Unlike a reference, a pointerneed not be initialized at the time it is defined. Like other built-in types,pointers defined at block scope have undefined value if they are notinitialized.

15、There are several ways toobtain a null pointer:

int *p1 = nullptr; // equivalent to int *p1 = 0;
int *p2 = 0;       // directly initializes p2 from the literal constant 0 
// must #include cstdlib
int *p3 = NULL;    // equivalent to int *p3 = 0;
ModernC++ programs generally should avoid using NULL and use nullptr instead.

16、A reference is not an object.Hence, we may not have a pointer to a reference. However, because a pointer isan object, we can define a reference to a pointer:

int i = 42;
int *p;        // p is a pointer to int
int *&r = p;   // r is a reference to the pointer p
r = &i; // r refers to a pointer; assigning &i to r makes p point to i 
*r = 0; // dereferencing r yields i, the object to which p points; changes i to 0

The easiest wayto understand the type of r is to read the definition right to left. The symbolclosest to the name of the variable (in this case the & in &r) is theone that has the most immediate effect on the variable’s type. Thus, we knowthat r is a reference. The rest of the declarator determines the type to whichr refers. The next symbol, * in this case, says that the type r refers to is apointer type. Finally, the base type of the declaration says that r is areference to a pointer to an int.

17、Because we can’t change thevalue of a const object after we create it, it must be initialized. As usual,the initializer may be an arbitrarily complicated expression:
const int i = get_size();  // ok: initialized at run time 
const int j = 42;          // ok: initialized at compile time 
const int k;               // error: k is uninitialized const

Among theoperations that don’t change the value of an object is initialization— when weuse an object to initialize another object, it doesn’t matter whether either orboth of the objects are consts:

int i = 42; 
const int ci = i;    // ok: the value in i is copied into ci 
int j = ci;          // ok: the value in ci is copied into j
18 
// file_1.cc defines and initializes a const that is accessible to other files 
extern const int bufSize = fcn(); 
// file_1.h 
extern const int bufSize; // same bufSize as defined in file_1.cc

Note:To share aconst object among multiple files, you must define the variable as extern.

19、References to const

const int ci = 1024; 
const int &r1 = ci;   // ok: both reference and underlying object are const 
r1 = 42;              // error: r1 is a reference to const
int &r2 = ci;         // error: non const reference to a const object<strong>
</strong>

we noted thatthere are two exceptions to the rule that the type of a reference must matchthe type of the object to which it refers. The first exception is that we caninitialize a reference to const from any expression that can be converted (§2.1.2, p. 35) to the type of the reference. In particular, we can bind areference to const to a nonconst object, a literal, or a more generalexpression:

int i = 42; 
const int &r1 = i;      // we can bind a const int& to a plain int object 
const int &r2 = 42;     // ok: r1 is a reference to const 
const int &r3 = r1 * 2;  // ok: r3 is a reference to const 
int &r4 = r1 * 2;        // error: r4 is a plain, non const reference

double dval = 3.14; 
const int &ri = dval;
《==》    
const int temp = dval;   // create a temporary const int from the double 
const int &ri = temp;    // bind ri to that temporary
20、Pointers and const
const double pi = 3.14;   // pi is const; its value may not be changed 
double *ptr = π        // error: ptr is a plain pointer 
const double *cptr = π // ok: cptr may point to a double that is const 
*cptr = 42;               // error: cannot assign to *cptr
double dval = 3.14;       // dval is a double; its value can be changed 
cptr = &dval;             // ok: but can't change dval through cptr
21、A constant expression is anexpression whose value cannot change and that can be evaluated at compile time.A literal is a constant expression. A const object that is initialized from aconstant expression is also a constant expression.
const int max_files = 20;    // max_files is a constant expression 
const int limit = max_files + 1; // limit is a constant expression
int staff_size = 27;       // staff_size is not a constant expression 
const int sz = get_size(); // sz is not a constant expression

Under the new standard, we can ask the compiler to verify that avariable is a constant expression by declaring the variable in a constexprdeclaration. Variables declared as constexpr are implicitly const and must beinitialized by constant expressions:

constexpr int mf = 20;        // 20 is a constant expression 
constexpr int limit = mf + 1; // mf + 1 is a constant expression 
constexpr int sz = size();    // ok only if size is a constexpr function

Generally, it isa good idea to use constexpr for variables that you intend to use as constantexpressions.

22、A type alias is a name that is a synonym for another type.

We candefine a type alias in one of two ways. Traditionally, we use a typedef:

typedef double wages;  // wages is a synonym for double
typedef wages base, *p; // base is a synonym for double, pfor double*

The new standard introduced a second way to define a typealias, via an alias declaration:

using SI = Sales_item; // SI is a synonym for Sales_item
23、Pointers, const, and Type Aliases
typedef char *pstring; 
const pstring cstr = 0; // cstr is a constant pointer to char 
const pstring *ps;      // ps is a pointer to a constant pointer to char
24

auto i = 0, *p = &i;      // ok: i is int and p is a pointer to int 
auto sz = 0, pi = 3.14;   // error: inconsistent types for sz and pi
int i = 0, &r = i; auto a = r;  // a is an int (r is an alias for i, which has type int)
const int ci = i, &cr = ci; auto b = ci;  // b is an int (top-level const in ci is dropped)
auto c = cr;  // c is an int (cr is an alias for ci whose const is top-level)
auto d = &i;  // d is an int*(& of an int object is int*)
auto e = &ci; // e is const int*(& of a const object is low-level const)
const auto f = ci; // deduced type of ci is int; f has type const int
auto &g = ci;       // g is a const int& that is bound to ci 
auto &h = 42;       // error: we can't bind a plain reference to a literal 
const auto &j = 42; // ok: we can bind a const reference to a literal
auto k = ci, &l = i;    // k is int; l is int& 
auto &m = ci, *p = &ci; // m is a const int&;p is a pointer to const int 
// error: type deduced from i is int; type deduced from &ci is const int 
auto &n = i, *p2 = &ci;

25、etimes we want to define avariable with a type that the compiler deduces from an expression but do notwant to use that expression to initialize the variable. For such cases, the newstandard introduced a second type specifier, decltype, which returns the typeof its operand. The compiler analyzes the expression to determine its type butdoes not evaluate the expression:

decltype(f()) sum = x; // sum has whatever type f returns

The way decltypehandles top-level const and references differs subtly from the way auto does.When the expression to which we apply decltype is a variable, decltype returnsthe type of that variable, including top-level const and references:

const int ci = 0, &cj = ci; 
decltype(ci) x = 0; // x has type const 
decltype(cj) y = x; // y has type const int& and is bound to x 
decltype(cj) z;     // error: z is a reference and must be initialized

decltypeand References

// decltype of an expression can be a reference type 
int i = 42, *p = &i, &r = i; 
decltype(r + 0) b;  // ok: addition yields an int; b is an (uninitialized) int 
decltype(*p) c;     // error: c is int& and must be initialized

// decltype of a parenthesized variable is always a reference 
decltype((i)) d;    // error: d is int& and must be initialized 
decltype(i) e;      // ok: e is an (uninitialized) int

Remember that decltype((variable )) (note,double parentheses) is always a reference type, but decltype( variable ) is areference type only if variable is a reference.

C++ Primer 读书笔记1