mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2024-03-22 13:30:58 +08:00
commit
aa8ff693cd
|
@ -1083,11 +1083,11 @@ Obviously, we cannot catch all errors through the static type system
|
|||
|
||||
In the following example, it is not clear from the interface what time_to_blink means: Seconds? Milliseconds?
|
||||
|
||||
void blink_led(int time_to_blink) //bad - the unit is ambiguous
|
||||
void blink_led(int time_to_blink) // bad - the unit is ambiguous
|
||||
{
|
||||
//...
|
||||
//do something with time_to_blink
|
||||
//...
|
||||
// ...
|
||||
// do something with time_to_blink
|
||||
// ...
|
||||
}
|
||||
|
||||
void use()
|
||||
|
@ -1099,11 +1099,11 @@ In the following example, it is not clear from the interface what time_to_blink
|
|||
|
||||
std::chrono::duration types introduced in C++11 helps making the unit of time duration explicit.
|
||||
|
||||
void blink_led(milliseconds time_to_blink) //good - the unit is explicit
|
||||
void blink_led(milliseconds time_to_blink) // good - the unit is explicit
|
||||
{
|
||||
//...
|
||||
//do something with time_to_blink
|
||||
//...
|
||||
// ...
|
||||
// do something with time_to_blink
|
||||
// ...
|
||||
}
|
||||
|
||||
void use()
|
||||
|
@ -1114,13 +1114,13 @@ std::chrono::duration types introduced in C++11 helps making the unit of time du
|
|||
The function can also be written in such a way that it will accept any time duration unit.
|
||||
|
||||
template<class rep, class period>
|
||||
void blink_led(duration<rep, period> time_to_blink) //good - accepts any unit
|
||||
void blink_led(duration<rep, period> time_to_blink) // good - accepts any unit
|
||||
{
|
||||
//assuming that millisecond is the smallest relevant unit
|
||||
// assuming that millisecond is the smallest relevant unit
|
||||
auto milliseconds_to_blink = duration_cast<milliseconds>(time_to_blink);
|
||||
//...
|
||||
//do something with milliseconds_to_blink
|
||||
//...
|
||||
// ...
|
||||
// do something with milliseconds_to_blink
|
||||
// ...
|
||||
}
|
||||
|
||||
void use()
|
||||
|
@ -1770,11 +1770,11 @@ If you write a non-trivial lambda that potentially can be used in more than one
|
|||
|
||||
##### Example
|
||||
|
||||
sort(a, b, [](T x, T y) { return x.valid() && y.valid() && x.value()<y.value(); });
|
||||
sort(a, b, [](T x, T y) { return x.valid() && y.valid() && x.value() < y.value(); });
|
||||
|
||||
Naming that lambda breaks up the expression into its logical parts and provides a strong hint to the meaning of the lambda.
|
||||
|
||||
auto lessT = [](T x, T y) { return x.valid() && y.valid() && x.value()<y.value(); };
|
||||
auto lessT = [](T x, T y) { return x.valid() && y.valid() && x.value() < y.value(); };
|
||||
|
||||
sort(a, b, lessT);
|
||||
find_if(a, b, lessT);
|
||||
|
@ -1947,7 +1947,7 @@ The (in)famous factorial:
|
|||
constexpr int max_exp = 17; // constexpr enables this to be used in Expects
|
||||
Expects(0 <= n && n < max_exp); // prevent silliness and overflow
|
||||
int x = 1;
|
||||
for (int i = 2; i <= n; ++i) x*= i;
|
||||
for (int i = 2; i <= n; ++i) x *= i;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
@ -2096,7 +2096,7 @@ Pure functions are easier to reason about, sometimes easier to optimize (and eve
|
|||
##### Example
|
||||
|
||||
template<class T>
|
||||
auto square(T t) { return t*t; }
|
||||
auto square(T t) { return t * t; }
|
||||
|
||||
##### Note
|
||||
|
||||
|
@ -3613,9 +3613,9 @@ If the `Handle` owns the object referred to by `s` it must have a destructor.
|
|||
|
||||
Independently of whether `Handle` owns its `Shape`, we must consider the default copy operations suspect:
|
||||
|
||||
Handle x {*new Circle{p1, 17}}; // the Handle had better own the Circle or we have a leak
|
||||
Handle x {*new Circle{p1, 17}}; // the Handle had better own the Circle or we have a leak
|
||||
Handle y {*new Triangle{p1, p2, p3}};
|
||||
x = y; // the default assignment will try *x.s=*y.s
|
||||
x = y; // the default assignment will try *x.s = *y.s
|
||||
|
||||
That `x=y` is highly suspect.
|
||||
Assigning a `Triangle` to a `Circle`?
|
||||
|
@ -4420,12 +4420,12 @@ After a copy `x` and `y` can be independent objects (value semantics, the way no
|
|||
|
||||
##### Example
|
||||
|
||||
class X2 { // OK: pointer semantics
|
||||
class X2 { // OK: pointer semantics
|
||||
public:
|
||||
X2();
|
||||
X2(const X&) = default; // shallow copy
|
||||
X2(const X&) = default; // shallow copy
|
||||
~X2() = default;
|
||||
void modify(); // change the value of X
|
||||
void modify(); // change the value of X
|
||||
// ...
|
||||
private:
|
||||
T* p;
|
||||
|
@ -4441,7 +4441,7 @@ After a copy `x` and `y` can be independent objects (value semantics, the way no
|
|||
X2 y = x;
|
||||
if (x != y) throw Bad{};
|
||||
x.modify();
|
||||
if (x != y) throw Bad{}; // assume pointer semantics
|
||||
if (x != y) throw Bad{}; // assume pointer semantics
|
||||
|
||||
##### Note
|
||||
|
||||
|
@ -4577,7 +4577,7 @@ Often, we can easily and cheaply do better: The standard library assumes that it
|
|||
|
||||
##### Note
|
||||
|
||||
Unless there is an exceptionally strong reason not to, make `x=std::move(y); y=z;` work with the conventional semantics.
|
||||
Unless there is an exceptionally strong reason not to, make `x = std::move(y); y = z;` work with the conventional semantics.
|
||||
|
||||
##### Enforcement
|
||||
|
||||
|
@ -4587,7 +4587,7 @@ Unless there is an exceptionally strong reason not to, make `x=std::move(y); y=z
|
|||
|
||||
##### Reason
|
||||
|
||||
If `x=x` changes the value of `x`, people will be surprised and bad errors may occur. However, people don't usually directly write a self-assignment that turn into a move, but it can occur. However, `std::swap` is implemented using move operations so if you accidentally do `swap(a, b)` where `a` and `b` refer to the same object, failing to handle self-move could be a serious and subtle error.
|
||||
If `x = x` changes the value of `x`, people will be surprised and bad errors may occur. However, people don't usually directly write a self-assignment that turn into a move, but it can occur. However, `std::swap` is implemented using move operations so if you accidentally do `swap(a, b)` where `a` and `b` refer to the same object, failing to handle self-move could be a serious and subtle error.
|
||||
|
||||
##### Example
|
||||
|
||||
|
@ -4965,7 +4965,10 @@ It is really hard to write a foolproof and useful `==` for a hierarchy.
|
|||
class B {
|
||||
string name;
|
||||
int number;
|
||||
virtual bool operator==(const B& a) const { return name == a.name && number == a.number; }
|
||||
virtual bool operator==(const B& a) const
|
||||
{
|
||||
return name == a.name && number == a.number;
|
||||
}
|
||||
// ...
|
||||
};
|
||||
|
||||
|
@ -4973,7 +4976,10 @@ It is really hard to write a foolproof and useful `==` for a hierarchy.
|
|||
|
||||
class D :B {
|
||||
char character;
|
||||
virtual bool operator==(const D& a) const { return name == a.name && number == a.number && character == a.character; }
|
||||
virtual bool operator==(const D& a) const
|
||||
{
|
||||
return name == a.name && number == a.number && character == a.character;
|
||||
}
|
||||
// ...
|
||||
};
|
||||
|
||||
|
@ -5267,7 +5273,7 @@ Copying a base is usually slicing. If you really need copy semantics, copy deepl
|
|||
|
||||
class base {
|
||||
public:
|
||||
virtual base* clone() =0;
|
||||
virtual base* clone() = 0;
|
||||
};
|
||||
|
||||
class derived : public base {
|
||||
|
@ -8415,7 +8421,7 @@ Avoid wrong results.
|
|||
|
||||
unsigned x = 100;
|
||||
unsigned y = 102;
|
||||
cout << abs(x-y) << '\n'; //wrong result
|
||||
cout << abs(x-y) << '\n'; // wrong result
|
||||
|
||||
##### Note
|
||||
|
||||
|
@ -8696,14 +8702,14 @@ Performance is very sensitive to cache performance and cache algorithms favor si
|
|||
|
||||
int matrix[rows][cols];
|
||||
|
||||
//bad
|
||||
for (int c=0; c<cols; ++c)
|
||||
for (int r=0; r<rows; ++r)
|
||||
// bad
|
||||
for (int c = 0; c < cols; ++c)
|
||||
for (int r = 0; r < rows; ++r)
|
||||
sum += matrix[r][c];
|
||||
|
||||
//good
|
||||
for (int r=0; r<rows; ++r)
|
||||
for (int c=0; c<cols; ++c)
|
||||
// good
|
||||
for (int r = 0; r < rows; ++r)
|
||||
for (int c = 0; c < cols; ++c)
|
||||
sum += matrix[r][c];
|
||||
|
||||
### <a name="Rper-context"></a> PER.30: Avoid context switches on the critical path
|
||||
|
@ -13245,7 +13251,7 @@ To simplify code and eliminate a need for explicit memory management. To bring a
|
|||
return ...;
|
||||
}
|
||||
|
||||
auto v = get_large_vector(); //return by value is ok, most modern compilers will do copy elision
|
||||
auto v = get_large_vector(); // return by value is ok, most modern compilers will do copy elision
|
||||
|
||||
##### Example
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user