mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2024-03-22 13:30:58 +08:00
commit
7f510892e5
|
@ -802,7 +802,6 @@ Excess checking can be costly.
|
|||
There are cases where checking early is dumb because you may not ever need the value, or may only need part of the value that is more easily checked than the whole. Similarly, don't add validity checks that change the asymptotic behavior of your interface (e.g., don't add a `O(n)` check to an interface with an average complexity of `O(1)`).
|
||||
|
||||
class Jet { // Physics says: e * e < x * x + y * y + z * z
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
@ -2101,7 +2100,6 @@ Consider:
|
|||
// simpleFunc: takes a value and calculates the expected ASIC output,
|
||||
// given the two mode flags.
|
||||
{
|
||||
|
||||
double intermediate;
|
||||
if (flag1 > 0) {
|
||||
intermediate = func1(val);
|
||||
|
@ -2118,9 +2116,10 @@ Consider:
|
|||
intermediate = func2(intermediate);
|
||||
}
|
||||
switch (flag2 / 10) {
|
||||
case 1: if (flag1 == -1) return finalize(intermediate, 1.171); break;
|
||||
case 1: if (flag1 == -1) return finalize(intermediate, 1.171);
|
||||
break;
|
||||
case 2: return finalize(intermediate, 13.1);
|
||||
default: ;
|
||||
default: break;
|
||||
}
|
||||
return finalize(intermediate, 0.);
|
||||
}
|
||||
|
@ -3338,7 +3337,7 @@ There is not a choice when a set of functions are used to do a semantically equi
|
|||
|
||||
##### See also
|
||||
|
||||
[Default arguments for virtual functions](#Rf-virtual-default-arg}
|
||||
[Default arguments for virtual functions](#Rh-virtual-default-arg)
|
||||
|
||||
##### Enforcement
|
||||
|
||||
|
@ -5668,14 +5667,18 @@ Asymmetric treatment of operands is surprising and a source of errors where conv
|
|||
int number;
|
||||
};
|
||||
|
||||
bool operator==(const X& a, const X& b) noexcept { return a.name == b.name && a.number == b.number; }
|
||||
bool operator==(const X& a, const X& b) noexcept {
|
||||
return a.name == b.name && a.number == b.number;
|
||||
}
|
||||
|
||||
##### Example, bad
|
||||
|
||||
class B {
|
||||
string name;
|
||||
int number;
|
||||
bool operator==(const B& a) const { return name == a.name && number == a.number; }
|
||||
bool operator==(const B& a) const {
|
||||
return name == a.name && number == a.number;
|
||||
}
|
||||
// ...
|
||||
};
|
||||
|
||||
|
@ -6503,7 +6506,8 @@ Capping an individual virtual function with `final` is error-prone as that `fina
|
|||
|
||||
class Widget { /* ... */ };
|
||||
|
||||
class My_widget final : public Widget { /* ... */ }; // nobody will ever want to improve My_widget (or so you thought)
|
||||
// nobody will ever want to improve My_widget (or so you thought)
|
||||
class My_widget final : public Widget { /* ... */ };
|
||||
|
||||
class My_improved_widget : public My_widget { /* ... */ }; // error: can't do that
|
||||
|
||||
|
@ -7458,7 +7462,7 @@ Such code is not uncommon in code written before there were convenient alternati
|
|||
|
||||
Use `constexpr` values instead. For example:
|
||||
|
||||
constexpr int red = 0x,FF0000;
|
||||
constexpr int red = 0xFF0000;
|
||||
constexpr short scale = 4;
|
||||
constexpr bool signed = true;
|
||||
|
||||
|
@ -8689,7 +8693,8 @@ Here, there is a chance that the reader knows what `trim_tail` means and that th
|
|||
Argument names of large functions are de facto non-local and should be meaningful:
|
||||
|
||||
void complicated_algorithm(vector<Record>& vr, const vector<int>& vi, map<string, int>& out)
|
||||
// read from events in vr (marking used Records) for the indices in vi placing (name, index) pairs into out
|
||||
// read from events in vr (marking used Records) for the indices in
|
||||
// vi placing (name, index) pairs into out
|
||||
{
|
||||
// ... 500 lines of code using vr, vi, and out ...
|
||||
}
|
||||
|
@ -9416,13 +9421,15 @@ Requires messy cast-and-macro-laden code to get working right.
|
|||
|
||||
#include <cstdarg>
|
||||
|
||||
void error(int severity ...) // "severity" followed by a zero-terminated list of char*s; write the C-style strings to cerr
|
||||
// "severity" followed by a zero-terminated list of char*s; write the C-style strings to cerr
|
||||
void error(int severity ...)
|
||||
{
|
||||
va_list ap; // a magic type for holding arguments
|
||||
va_start(ap, severity); // arg startup: "severity" is the first argument of error()
|
||||
|
||||
for (;;) {
|
||||
char* p = va_arg(ap, char*); // treat the next var as a char*; no checking: a cast in disguise
|
||||
// treat the next var as a char*; no checking: a cast in disguise
|
||||
char* p = va_arg(ap, char*);
|
||||
if (p == nullptr) break;
|
||||
cerr << p << ' ';
|
||||
}
|
||||
|
@ -11452,11 +11459,11 @@ Defining "small amount" precisely is impossible.
|
|||
##### Example
|
||||
|
||||
string modify1(string);
|
||||
void modify2(shared_ptr<string);
|
||||
void modify2(shared_ptr<string>);
|
||||
|
||||
void fct(string& s)
|
||||
{
|
||||
auto res = async(modify1,string);
|
||||
auto res = async(modify1, s);
|
||||
async(modify2, &s);
|
||||
}
|
||||
|
||||
|
@ -11529,7 +11536,7 @@ Thread creation is expensive.
|
|||
void master(istream& is)
|
||||
{
|
||||
for (Message m; is >> m; )
|
||||
run_list.push_back(new thread(worker,m);}
|
||||
run_list.push_back(new thread(worker, m));
|
||||
}
|
||||
|
||||
This spawns a `thread` per message, and the `run_list` is presumably managed to destroy those tasks once they are finished.
|
||||
|
@ -12086,7 +12093,7 @@ The `File_handle` constructor might defined like this:
|
|||
:f{fopen(name.c_str(), mode.c_str())}
|
||||
{
|
||||
if (!f)
|
||||
throw runtime_error{"File_handle: could not open "S-+ name + " as " + mode"}
|
||||
throw runtime_error{"File_handle: could not open " + name + " as " + mode};
|
||||
}
|
||||
|
||||
##### Note
|
||||
|
@ -12175,7 +12182,7 @@ Not all member functions can be called.
|
|||
// if elem!=nullptr then elem points to sz doubles
|
||||
public:
|
||||
vector() : elem{nullptr}, sz{0}{}
|
||||
vctor(int s) : elem{new double},sz{s} { /* initialize elements */ }
|
||||
vector(int s) : elem{new double}, sz{s} { /* initialize elements */ }
|
||||
~vector() { delete elem; }
|
||||
|
||||
double& operator[](int s) { return elem[s]; }
|
||||
|
@ -14353,7 +14360,6 @@ This looks innocent enough, but ???
|
|||
// requires Regular<T> && Allocator<A>
|
||||
class List2 {
|
||||
public:
|
||||
|
||||
using iterator = Link<T>*;
|
||||
|
||||
iterator first() const { return head; }
|
||||
|
@ -16511,6 +16517,7 @@ Also, `std::array<>::fill()` or `std::fill()` or even an empty initializer are b
|
|||
fill(b, 0); // std::fill() + Ranges TS
|
||||
|
||||
if ( a == b ) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16755,7 +16762,8 @@ Code says what is done, not what is supposed to be done. Often intent can be sta
|
|||
##### Example
|
||||
|
||||
void stable_sort(Sortable& c)
|
||||
// sort c in the order determined by <, keep equal elements (as defined by ==) in their original relative order
|
||||
// sort c in the order determined by <, keep equal elements (as defined by ==) in
|
||||
// their original relative order
|
||||
{
|
||||
// ... quite a few lines of non-trivial code ...
|
||||
}
|
||||
|
@ -17166,8 +17174,8 @@ It is really easy to overlook a statement when there is more on a line.
|
|||
|
||||
##### Example
|
||||
|
||||
int x = 7; char* p = 29; // don’t
|
||||
int x = 7; f(x); ++x; // don’t
|
||||
int x = 7; char* p = 29; // don't
|
||||
int x = 7; f(x); ++x; // don't
|
||||
|
||||
##### Enforcement
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user