最近在看这个:learncpp.com
主要是一些我自己容易忽视的地方
记一些笔记在下面,章节序号对应主页的章节序号,还有错漏地方请不吝赐教
CH1.3a
Rule: Avoid "using" statement outside of a function body.
======
CH1.10
The preprocessor copies the contents of the included file into the including file at the point of the #include directive
Conditional Compilation:
#ifndef SOME_UNIQUE_NAME_HERE
#define SOME_UNIQUE_NAME_HERE
#endif
======
CH2.1
Favor implicit initialization over explicit initialization
int nValue = 5; // explicit initialization
int nValue(5); // implicit initialization
Uniform(list) initialization in C++11
int value{}; // default initialization to 0
int value{4.5}; // error: an integer variable can not hold a non-integer value
If you’re using a C++11 compatible compiler, favor uniform initialization
======
CH2.4
While short int, long int, and long long int are valid, the shorthand versions short, long, and long long should be preferred. In addition to being less typing, adding the prefix int makes the type harder to distinguish from variables of type int. This can lead to mistakes if the short or long modifier is inadvertently missed.
long long int lli; // valid
long long ll; // preferred
All integer variables except char are signed by default. Char can be either signed or unsigned by default (but is usually signed for conformity).
Generally, the signed keyword is not used (since it’s redundant), except on chars (when necessary to ensure they are signed).
Favor signed integers over unsigned integers
======
CH2.4a
<cstdint>:fixed width integers: int8_t/uint8_t/...uint64_t
Until this is clarified by a future draft of C++, you should assume that int8_t and uint8_t may or may not behave like char types.
int can be used when the integer size doesn’t matter and isn’t going to be large.
Fixed-width integers should be used in all other cases.
Only use unsigned types if you have a compelling reason.
======
CH2.5
Summation precision: Kahan summation algorithm
#include <iomanip> // for std::setprecision()
Float values have between 6 and 9 digits of precision, with most float values having at least 7 significant digits. Double values have between 15 and 18 digits of precision, with most double values having at least 16 significant digits. Long double has a minimum precision of 15, 18, or 33 significant digits depending on how many bytes it occupies.
Favor double over float unless space is at a premium, as the lack of precision in a float will often lead to challenges.
Rounding Error matters: 0.1+...+0.1 \neq 1.0. Ref. CH3.5 -- Relational operators
======
CH2.6
ture is evaluated as 1
======
CH2.7
Note that even though cin will let you enter multiple characters, ch will only hold 1 character. Consequently, only the first input character is placed in ch. The rest of the user input is left in the input buffer that cin uses, and can be accessed with subsequent calls to cin.
\n and endl:
Use std::endl when you need to ensure your output is output immediately (e.g. when writing a record to a file, or when updating a progress bar). Note that this may have a performance cost, particularly if writing to the output device is slow (e.g. when writing a file to a disk).
Use ‘\n’ in other cases.
wchar_t should be avoided in almost all cases (except when interfacing with the Windows API). Its size is implementation defined, and is not reliable. It has largely been deprecated.
You won’t need to use char16_t(UTF-16) or char32_t(UTF-32) unless you’re planning on making your program Unicode compatible and you are using 16-bit or 32-bit Unicode characters.
======
CH2.8
0x 16; 0 8; 0b 2(C++14)
======
CH2.9
Making a function parameter const does two things. First, it tells the person calling the function that the function will not change the value of myValue. Second, it ensures that the function doesn’t change the value of myValue.
Any variable that should not change values after initialization should be declared as const (or constexpr in C++11).
Avoid using #define to create symbolic constants, but use const variables to provide a name and context for your magic numbers.
A recommended way:
1) Create a header file to hold these constants
2) Inside this header file, declare a namespace
3) Add all your constants inside the namespace (make sure they’re const)
4) #include the header file wherever you need it
Use the scope resolution operator (::) to access your constants in .cpp files
======
CH3.2
Prior to C++11, if either of the operands of integer division are negative, the compiler is free to round up or down! For example, -5 / 2 can evaluate to either -3 or -2, depending on which way the compiler rounds. However, most modern compilers truncate towards 0 (so -5 / 2 would equal -2). The C++11 specification changed this to explicitly define that integer division should always truncate towards 0 (or put more simply, the fractional component is dropped).
Also prior to C++11, if either operand of the modulus operator is negative, the results of the modulus can be either negative or positive! For example, -5 % 2 can evaluate to either 1 or -1. The C++11 specification tightens this up so that a % b always resolves to the sign of a.
======
CH3.3
Be aware of undefined expressions like:x = x++;
Don’t use a variable that has a side effect( if it modifies some state) applied to it more than once in a given statement.
======
CH3.4
Avoid using the comma operator, except within for loops.
Only use the conditional operator for simple conditionals where it enhances readability.
It’s worth noting that the conditional operator evaluates as an expression, whereas if/else evaluates as statements. This means the conditional operator can be used in some places where if/else can not.
For example, when initializing a const variable:
bool inBigClassroom = false;
const int classSize = inBigClassroom ? 30 : 20;
There’s no satisfactory if/else statement for this, since const variables must be initialized when defined, and the initializer can’t be a statement.
======
CH3.5
Directly comparing floating point values using any of these operators is dangerous. This is because small rounding errors in the floating point operands may cause unexpected results.
Donald Knuth, a famous computer scientist, suggested the following method in his book “The Art of Computer Programming, Volume II: Seminumerical Algorithms (Addison-Wesley, 1969)”:
#include <cmath>
// return true if the difference between a and b is within epsilon percent of the larger of a and b
bool approximatelyEqual(double a, double b, double epsilon)
{
return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}
The author suggests the following approach
// return true if the difference between a and b is less than absEpsilon, or within relEpsilon percent of the larger of a and b
bool approximatelyEqualAbsRel(double a, double b, double absEpsilon, double relEpsilon)
{
// Check if the numbers are really close -- needed when comparing numbers near zero.
double diff = fabs(a - b);
if (diff <= absEpsilon)
return true;
// Otherwise fall back to Knuth‘s algorithm
return diff <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * relEpsilon);
}
Comparison of floating point numbers is a difficult topic, and there’s no “one size fits all” algorithm that works for every case.
======
CH3.6
Any non-zero integer value evaluates to true when used in a boolean context. Mixing integer and boolean operations can be very confusing, and should be avoided!
Short circuit evaluation presents another opportunity to show why operators that cause side effects should not be used.
======
CH3.8
When dealing with bit operators, use unsigned integers.
Note that the results of applying the bitwise shift operators to a signed integer are compiler dependent.
======
CH3.8a
Bit mask and bit flags:
Bit flags are typically used in two cases:
1) When you have many sets of identical bitflags.
2) Set options easily especially there are a lot of options (consider f(arg1,arg2...arg100))
manage bitflags:std::bitset
Bit mask: one application: color channel
======
CH4.1
Note that variables inside nested blocks can have the same name as variable inside outer blocks. When this happens, the nested variable “hides” the outer variable. This is called name hiding or shadowing.
======
CH4.2
By convention, many developers prefix global variable names with “g_” to indicate that they are global. This both helps identify global variables as well as avoids naming conflicts with local variables.
By default, non-const variables declared outside of a block are assumed to be external. However, const variables declared outside of a block are assumed to be internal.
Encapsulate the global variable.
======
CH4.3
Static variables offer some of the benefit of global variables (they don’t get destroyed until the end of the program) while limiting their visibility to block scope. This makes them much safer for use than global variables.
C++笔记(to be cont'd)