mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2024-03-22 13:30:58 +08:00
Fix code that does not compile
This commit is contained in:
parent
a4c8444032
commit
fca180e978
|
@ -718,23 +718,23 @@ The date is validated twice (by the `Date` constructor) and passed as a characte
|
||||||
There are cases where checking early is dumb because you may not ever need the value,
|
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.
|
or may only need part of the value that is more easily checked than the whole.
|
||||||
|
|
||||||
class Jet { // Physics says: e*e < x*x + y*y + z*z
|
class Jet { // Physics says: e*e < x*x + y*y + z*z
|
||||||
float fx, fy, fz, fe;
|
float fx, fy, fz, fe;
|
||||||
public:
|
public:
|
||||||
Jet(float x, float y, float z, float e)
|
Jet(float x, float y, float z, float e)
|
||||||
:fx(x), fy(y), fz(z), fe(e)
|
:fx(x), fy(y), fz(z), fe(e)
|
||||||
{
|
{
|
||||||
// Should I check the here that the values are physically meaningful?
|
// Should I check the here that the values are physically meaningful?
|
||||||
}
|
}
|
||||||
|
|
||||||
float m() const
|
float m() const
|
||||||
{
|
{
|
||||||
// Should I handle the degenerate case here?
|
// Should I handle the degenerate case here?
|
||||||
return sqrt(x*x + y*y + z*z - e*e);
|
return sqrt(x*x + y*y + z*z - e*e);
|
||||||
}
|
}
|
||||||
|
|
||||||
???
|
???
|
||||||
};
|
};
|
||||||
|
|
||||||
The physical law for a jet (`e*e < x*x + y*y + z*z`) is not an invariant because the possibility of measurement errors.
|
The physical law for a jet (`e*e < x*x + y*y + z*z`) is not an invariant because the possibility of measurement errors.
|
||||||
|
|
||||||
|
@ -2585,8 +2585,8 @@ Subsections:
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
void draw(int x, int y, int x2, int y2); // BAD: unnecessary implicit relationships
|
void draw(int x, int y, int x2, int y2); // BAD: unnecessary implicit relationships
|
||||||
void draw(Point from, Point to) // better
|
void draw(Point from, Point to); // better
|
||||||
|
|
||||||
**Note**: A simple class without virtual functions implies no space or time overhead.
|
**Note**: A simple class without virtual functions implies no space or time overhead.
|
||||||
|
|
||||||
|
@ -3024,7 +3024,7 @@ The whole purpose of `final_action` is to get a piece of code (usually a lambda)
|
||||||
string s;
|
string s;
|
||||||
int i;
|
int i;
|
||||||
vector<int> vi;
|
vector<int> vi;
|
||||||
}
|
};
|
||||||
|
|
||||||
The default destructor does it better, more efficiently, and can't get it wrong.
|
The default destructor does it better, more efficiently, and can't get it wrong.
|
||||||
|
|
||||||
|
@ -3353,7 +3353,7 @@ It is often a good idea to express the invariant as an `Ensure` on the construct
|
||||||
struct Rec2{
|
struct Rec2{
|
||||||
string s;
|
string s;
|
||||||
int i;
|
int i;
|
||||||
Rec2(const string& ss, int ii = 0} :s{ss}, i{ii} {} // redundant
|
Rec2(const string& ss, int ii = 0) :s{ss}, i{ii} {} // redundant
|
||||||
};
|
};
|
||||||
|
|
||||||
Rec r1 {"Foo", 7};
|
Rec r1 {"Foo", 7};
|
||||||
|
@ -3413,7 +3413,7 @@ The idiom of having constructors acquire resources and destructors release them
|
||||||
// ...
|
// ...
|
||||||
public:
|
public:
|
||||||
X2(const string& name)
|
X2(const string& name)
|
||||||
:f{fopen(name.c_str(), "r"}
|
:f{fopen(name.c_str(), "r")}
|
||||||
{
|
{
|
||||||
if (f==nullptr) throw runtime_error{"could not open" + name};
|
if (f==nullptr) throw runtime_error{"could not open" + name};
|
||||||
// ...
|
// ...
|
||||||
|
@ -3438,7 +3438,7 @@ The idiom of having constructors acquire resources and destructors release them
|
||||||
// ...
|
// ...
|
||||||
public:
|
public:
|
||||||
X3(const string& name)
|
X3(const string& name)
|
||||||
:f{fopen(name.c_str(), "r"}, valid{false}
|
:f{fopen(name.c_str(), "r")}, valid{false}
|
||||||
{
|
{
|
||||||
if (f) valid=true;
|
if (f) valid=true;
|
||||||
// ...
|
// ...
|
||||||
|
@ -3451,7 +3451,7 @@ The idiom of having constructors acquire resources and destructors release them
|
||||||
|
|
||||||
void f()
|
void f()
|
||||||
{
|
{
|
||||||
X3 file {Heraclides"};
|
X3 file {"Heraclides"};
|
||||||
file.read(); // crash or bad read!
|
file.read(); // crash or bad read!
|
||||||
// ...
|
// ...
|
||||||
if (is_valid()()) {
|
if (is_valid()()) {
|
||||||
|
@ -3881,6 +3881,7 @@ Types can be defined to move for logical as well as performance reasons.
|
||||||
T* elem;
|
T* elem;
|
||||||
int sz;
|
int sz;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Vector& Vector::operator=(const Vector& a)
|
Vector& Vector::operator=(const Vector& a)
|
||||||
{
|
{
|
||||||
|
@ -4049,6 +4050,7 @@ Consider:
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
class X { // OK: value semantics
|
class X { // OK: value semantics
|
||||||
public:
|
public:
|
||||||
X();
|
X();
|
||||||
|
@ -4134,6 +4136,7 @@ A non-throwing move will be used more efficiently by standard-library and langua
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
class Vector {
|
class Vector {
|
||||||
// ...
|
// ...
|
||||||
Vector(Vector&& a) noexcept :elem{a.elem}, sz{a.sz} { a.sz=0; a.elem=nullptr; }
|
Vector(Vector&& a) noexcept :elem{a.elem}, sz{a.sz} { a.sz=0; a.elem=nullptr; }
|
||||||
|
@ -4148,6 +4151,7 @@ These copy operations do not throw.
|
||||||
|
|
||||||
**Example, bad**:
|
**Example, bad**:
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
class Vector2 {
|
class Vector2 {
|
||||||
// ...
|
// ...
|
||||||
Vector2(Vector2&& a) { *this = a; } // just use the copy
|
Vector2(Vector2&& a) { *this = a; } // just use the copy
|
||||||
|
@ -6414,8 +6418,8 @@ or better using concepts
|
||||||
or
|
or
|
||||||
|
|
||||||
double scalbn( // better: x*pow(FLT_RADIX, n); FLT_RADIX is usually 2
|
double scalbn( // better: x*pow(FLT_RADIX, n); FLT_RADIX is usually 2
|
||||||
double x; // base value
|
double x, // base value
|
||||||
int n; // exponent
|
int n // exponent
|
||||||
);
|
);
|
||||||
|
|
||||||
or
|
or
|
||||||
|
@ -6439,7 +6443,7 @@ or
|
||||||
auto s = v.size();
|
auto s = v.size();
|
||||||
auto h = t.future();
|
auto h = t.future();
|
||||||
auto q = new int[s];
|
auto q = new int[s];
|
||||||
auto f = [](int x){ return x+10; }
|
auto f = [](int x){ return x+10; };
|
||||||
|
|
||||||
In each case, we save writing a longish, hard-to-remember type that the compiler already knows but a programmer could get wrong.
|
In each case, we save writing a longish, hard-to-remember type that the compiler already knows but a programmer could get wrong.
|
||||||
|
|
||||||
|
@ -8066,7 +8070,7 @@ One strategy is to add a `valid()` operation to every resource handle:
|
||||||
|
|
||||||
void f()
|
void f()
|
||||||
{
|
{
|
||||||
Vector<string> vs(100); // not std::vector: valid() added
|
vector<string> vs(100); // not std::vector: valid() added
|
||||||
if (!vs.valid()) {
|
if (!vs.valid()) {
|
||||||
// handle error or exit
|
// handle error or exit
|
||||||
}
|
}
|
||||||
|
@ -8606,7 +8610,7 @@ It also avoids brittle or inefficient workarounds. Convention: That's the way th
|
||||||
int sz;
|
int sz;
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector<double> v(10);
|
vector<double> v(10);
|
||||||
v[7] = 9.9;
|
v[7] = 9.9;
|
||||||
|
|
||||||
**Example, bad**:
|
**Example, bad**:
|
||||||
|
@ -9441,14 +9445,14 @@ The two language mechanisms can be use effectively in combination, but a few des
|
||||||
// ...
|
// ...
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector<int> vi;
|
vector<int> vi;
|
||||||
Vector<string> vs;
|
vector<string> vs;
|
||||||
|
|
||||||
It is probably a dumb idea to define a `sort` as a member function of a container,
|
It is probably a dumb idea to define a `sort` as a member function of a container,
|
||||||
but it is not unheard of and it makes a good example of what not to do.
|
but it is not unheard of and it makes a good example of what not to do.
|
||||||
|
|
||||||
Given this, the compiler cannot know if `Vector<int>::sort()` is called, so it must generate code for it.
|
Given this, the compiler cannot know if `vector<int>::sort()` is called, so it must generate code for it.
|
||||||
Similar for `Vector<string>::sort()`.
|
Similar for `vector<string>::sort()`.
|
||||||
Unless those two functions are called that's code bloat.
|
Unless those two functions are called that's code bloat.
|
||||||
Imagine what this would do to a class hierarchy with dozens of member functions and dozens of derived classes with many instantiations.
|
Imagine what this would do to a class hierarchy with dozens of member functions and dozens of derived classes with many instantiations.
|
||||||
|
|
||||||
|
@ -10798,8 +10802,8 @@ Issue a diagnostic for any indexing expression on an expression or variable of a
|
||||||
|
|
||||||
void f(int i, int j)
|
void f(int i, int j)
|
||||||
{
|
{
|
||||||
a[i + j] = 12; // BAD, could be rewritten as...
|
a[i + j] = 12; // BAD, could be rewritten as...
|
||||||
at(a, i + j) = 12; // OK - bounds-checked
|
at(a, i + j) = 12; // OK - bounds-checked
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11966,7 +11970,7 @@ Now `Named` has a default constructor, a destructor, and efficient copy and move
|
||||||
|
|
||||||
template<typename T> class Vector {
|
template<typename T> class Vector {
|
||||||
public:
|
public:
|
||||||
Vector<std::initializer_list<T>);
|
vector<std::initializer_list<T>>;
|
||||||
// ...
|
// ...
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user