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
|
@ -2586,7 +2586,7 @@ Subsections:
|
|||
**Example**:
|
||||
|
||||
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.
|
||||
|
||||
|
@ -3024,7 +3024,7 @@ The whole purpose of `final_action` is to get a piece of code (usually a lambda)
|
|||
string s;
|
||||
int i;
|
||||
vector<int> vi;
|
||||
}
|
||||
};
|
||||
|
||||
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{
|
||||
string s;
|
||||
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};
|
||||
|
@ -3413,7 +3413,7 @@ The idiom of having constructors acquire resources and destructors release them
|
|||
// ...
|
||||
public:
|
||||
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};
|
||||
// ...
|
||||
|
@ -3438,7 +3438,7 @@ The idiom of having constructors acquire resources and destructors release them
|
|||
// ...
|
||||
public:
|
||||
X3(const string& name)
|
||||
:f{fopen(name.c_str(), "r"}, valid{false}
|
||||
:f{fopen(name.c_str(), "r")}, valid{false}
|
||||
{
|
||||
if (f) valid=true;
|
||||
// ...
|
||||
|
@ -3451,7 +3451,7 @@ The idiom of having constructors acquire resources and destructors release them
|
|||
|
||||
void f()
|
||||
{
|
||||
X3 file {Heraclides"};
|
||||
X3 file {"Heraclides"};
|
||||
file.read(); // crash or bad read!
|
||||
// ...
|
||||
if (is_valid()()) {
|
||||
|
@ -3881,6 +3881,7 @@ Types can be defined to move for logical as well as performance reasons.
|
|||
T* elem;
|
||||
int sz;
|
||||
};
|
||||
}
|
||||
|
||||
Vector& Vector::operator=(const Vector& a)
|
||||
{
|
||||
|
@ -4049,6 +4050,7 @@ Consider:
|
|||
|
||||
**Example**:
|
||||
|
||||
template<typename T>
|
||||
class X { // OK: value semantics
|
||||
public:
|
||||
X();
|
||||
|
@ -4134,6 +4136,7 @@ A non-throwing move will be used more efficiently by standard-library and langua
|
|||
|
||||
**Example**:
|
||||
|
||||
template<typename T>
|
||||
class Vector {
|
||||
// ...
|
||||
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**:
|
||||
|
||||
template<typename T>
|
||||
class Vector2 {
|
||||
// ...
|
||||
Vector2(Vector2&& a) { *this = a; } // just use the copy
|
||||
|
@ -6414,8 +6418,8 @@ or better using concepts
|
|||
or
|
||||
|
||||
double scalbn( // better: x*pow(FLT_RADIX, n); FLT_RADIX is usually 2
|
||||
double x; // base value
|
||||
int n; // exponent
|
||||
double x, // base value
|
||||
int n // exponent
|
||||
);
|
||||
|
||||
or
|
||||
|
@ -6439,7 +6443,7 @@ or
|
|||
auto s = v.size();
|
||||
auto h = t.future();
|
||||
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.
|
||||
|
||||
|
@ -8066,7 +8070,7 @@ One strategy is to add a `valid()` operation to every resource handle:
|
|||
|
||||
void f()
|
||||
{
|
||||
Vector<string> vs(100); // not std::vector: valid() added
|
||||
vector<string> vs(100); // not std::vector: valid() added
|
||||
if (!vs.valid()) {
|
||||
// handle error or exit
|
||||
}
|
||||
|
@ -8606,7 +8610,7 @@ It also avoids brittle or inefficient workarounds. Convention: That's the way th
|
|||
int sz;
|
||||
};
|
||||
|
||||
Vector<double> v(10);
|
||||
vector<double> v(10);
|
||||
v[7] = 9.9;
|
||||
|
||||
**Example, bad**:
|
||||
|
@ -9441,14 +9445,14 @@ The two language mechanisms can be use effectively in combination, but a few des
|
|||
// ...
|
||||
};
|
||||
|
||||
Vector<int> vi;
|
||||
Vector<string> vs;
|
||||
vector<int> vi;
|
||||
vector<string> vs;
|
||||
|
||||
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.
|
||||
|
||||
Given this, the compiler cannot know if `Vector<int>::sort()` is called, so it must generate code for it.
|
||||
Similar for `Vector<string>::sort()`.
|
||||
Given this, the compiler cannot know if `vector<int>::sort()` is called, so it must generate code for it.
|
||||
Similar for `vector<string>::sort()`.
|
||||
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.
|
||||
|
||||
|
@ -11966,7 +11970,7 @@ Now `Named` has a default constructor, a destructor, and efficient copy and move
|
|||
|
||||
template<typename T> class Vector {
|
||||
public:
|
||||
Vector<std::initializer_list<T>);
|
||||
vector<std::initializer_list<T>>;
|
||||
// ...
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user