@@ -3524,7 +3524,6 @@ but:
3524
3524
int y;
3525
3525
Month m;
3526
3526
char d; // day
3527
- Date(int yy, Month mm, char dd);
3528
3527
};
3529
3528
3530
3529
##### Note
@@ -4169,7 +4168,7 @@ Note that if you define a destructor, you must define or delete [all default ope
4169
4168
~Smart_ptr2() { delete p; } // p is an owner!
4170
4169
};
4171
4170
4172
- void use(Smart_ptr <int> p1)
4171
+ void use(Smart_ptr2 <int> p1)
4173
4172
{
4174
4173
auto p2 = p1; // error: double deletion
4175
4174
}
@@ -4279,7 +4278,7 @@ See [this in the Discussion section](#Sd-dtor).
4279
4278
##### Example, bad
4280
4279
4281
4280
struct Base { // BAD: no virtual destructor
4282
- virtual f();
4281
+ virtual void f();
4283
4282
};
4284
4283
4285
4284
struct D : Base {
@@ -4440,8 +4439,8 @@ The C++11 initializer list rule eliminates the need for many constructors. For e
4440
4439
Rec2(const string& ss, int ii = 0) :s{ss}, i{ii} {} // redundant
4441
4440
};
4442
4441
4443
- Rec r1 {"Foo", 7};
4444
- Rec r2 {"Bar"};
4442
+ Rec2 r1 {"Foo", 7};
4443
+ Rec2 r2 {"Bar"};
4445
4444
4446
4445
The `Rec2` constructor is redundant.
4447
4446
Also, the default for `int` would be better done as a [member initializer](#Rc-in-class-initializer).
@@ -4532,7 +4531,7 @@ Leaving behind an invalid object is asking for trouble.
4532
4531
// ...
4533
4532
}
4534
4533
4535
- void is_valid() { return valid; }
4534
+ bool is_valid() { return valid; }
4536
4535
void read(); // read from f
4537
4536
// ...
4538
4537
};
@@ -4542,7 +4541,7 @@ Leaving behind an invalid object is asking for trouble.
4542
4541
X3 file {"Heraclides"};
4543
4542
file.read(); // crash or bad read!
4544
4543
// ...
4545
- if (is_valid()) {
4544
+ if (file. is_valid()) {
4546
4545
file.read();
4547
4546
// ...
4548
4547
}
@@ -4619,7 +4618,7 @@ A class with members that all have default constructors implicitly gets a defaul
4619
4618
4620
4619
struct X {
4621
4620
string s;
4622
- vector v;
4621
+ vector<int> v;
4623
4622
};
4624
4623
4625
4624
X x; // means X{{}, {}}; that is the empty string and the empty vector
@@ -4945,7 +4944,7 @@ To avoid repetition and accidental differences.
4945
4944
int y;
4946
4945
public:
4947
4946
Date(int ii, Month mm, year yy)
4948
- :i{ii}, m{mm} y{yy}
4947
+ :i{ii}, m{mm}, y{yy}
4949
4948
{ if (!valid(i, m, y)) throw Bad_date{}; }
4950
4949
4951
4950
Date(int ii, Month mm)
@@ -4964,7 +4963,7 @@ The common action gets tedious to write and may accidentally not be common.
4964
4963
int y;
4965
4964
public:
4966
4965
Date2(int ii, Month mm, year yy)
4967
- :i{ii}, m{mm} y{yy}
4966
+ :i{ii}, m{mm}, y{yy}
4968
4967
{ if (!valid(i, m, y)) throw Bad_date{}; }
4969
4968
4970
4969
Date2(int ii, Month mm)
@@ -5476,9 +5475,9 @@ Because we defined the destructor, we must define the copy and move operations.
5476
5475
~Tracer2() { cerr << "exiting " << message << '\n'; }
5477
5476
5478
5477
Tracer2(const Tracer2& a) : message{a.message} {}
5479
- Tracer2& operator=(const Tracer2& a) { message = a.message; }
5478
+ Tracer2& operator=(const Tracer2& a) { message = a.message; return *this; }
5480
5479
Tracer2(Tracer2&& a) :message{a.message} {}
5481
- Tracer2& operator=(Tracer2&& a) { message = a.message; }
5480
+ Tracer2& operator=(Tracer2&& a) { message = a.message; return *this; }
5482
5481
};
5483
5482
5484
5483
Writing out the bodies of the copy and move operations is verbose, tedious, and error-prone. A compiler does it better.
@@ -6231,7 +6230,7 @@ but bear with us because this is just a simple example of a technique aimed at m
6231
6230
6232
6231
6233
6232
class Impl::Circle : public Circle, public Impl::Shape { // implementation
6234
- publc :
6233
+ public :
6235
6234
// constructors, destructor
6236
6235
6237
6236
int radius() { /* ... */ }
@@ -6246,7 +6245,7 @@ And we could extend the hierarchies by adding a Smiley class (:-)):
6246
6245
};
6247
6246
6248
6247
class Impl::Smiley : Public Smiley, public Impl::Circle { // implementation
6249
- publc :
6248
+ public :
6250
6249
// constructors, destructor
6251
6250
// ...
6252
6251
}
@@ -7105,7 +7104,7 @@ Avoiding inconsistent definition in different namespaces
7105
7104
bool operator==(S, S); // OK: in the same namespace as S, and even next to S
7106
7105
S s;
7107
7106
7108
- bool s == s;
7107
+ bool x = ( s == s) ;
7109
7108
7110
7109
This is what a default `==` would do, if we had such defaults.
7111
7110
@@ -7118,7 +7117,7 @@ This is what a default `==` would do, if we had such defaults.
7118
7117
7119
7118
N::S s;
7120
7119
7121
- bool s == s; // finds N::operator==() by ADL
7120
+ bool x = ( s == s) ; // finds N::operator==() by ADL
7122
7121
7123
7122
##### Example, bad
7124
7123
@@ -7456,7 +7455,7 @@ If you can't name an enumeration, the values are not related
7456
7455
7457
7456
##### Example, bad
7458
7457
7459
- enum { red = 0xFF0000, scale = 4, signed = 1 };
7458
+ enum { red = 0xFF0000, scale = 4, is_signed = 1 };
7460
7459
7461
7460
Such code is not uncommon in code written before there were convenient alternative ways of specifying integer constants.
7462
7461
@@ -7466,7 +7465,7 @@ Use `constexpr` values instead. For example:
7466
7465
7467
7466
constexpr int red = 0xFF0000;
7468
7467
constexpr short scale = 4;
7469
- constexpr bool signed = true;
7468
+ constexpr bool is_signed = true;
7470
7469
7471
7470
##### Enforcement
7472
7471
@@ -7519,8 +7518,8 @@ The default gives a consecutive set of values that is good for `switch`-statemen
7519
7518
##### Example
7520
7519
7521
7520
enum class Col1 { red, yellow, blue };
7522
- enum class Col2 { red = 1, red = 2, blue = 2 }; // typo
7523
- enum class Month { jan = 1, feb, mar, apr, mar , jun,
7521
+ enum class Col2 { red = 1, yellow = 2, blue = 2 }; // typo
7522
+ enum class Month { jan = 1, feb, mar, apr, may , jun,
7524
7523
jul, august, sep, oct, nov, dec }; // starting with 1 is conventional
7525
7524
enum class Base_flag { dec = 1, oct = dec << 1, hex = dec << 2 }; // set of bits
7526
7525
@@ -8533,7 +8532,7 @@ The more traditional and lower-level near-equivalent is longer, messier, harder
8533
8532
is.read(s, maxstring);
8534
8533
res[elemcount++] = s;
8535
8534
}
8536
- nread = elemcount;
8535
+ nread = & elemcount;
8537
8536
return res;
8538
8537
}
8539
8538
@@ -11114,7 +11113,7 @@ Avoids nasty errors from unreleased locks.
11114
11113
11115
11114
Sooner or later, someone will forget the `mtx.unlock()`, place a `return` in the `... do stuff ...`, throw an exception, or something.
11116
11115
11117
- mutex mtx;
11116
+ mutex mtx;
11118
11117
11119
11118
void do_stuff()
11120
11119
{
@@ -11363,7 +11362,7 @@ The plain `thread`s should be assumed to use the full generality of `std::thread
11363
11362
11364
11363
void use(int n)
11365
11364
{
11366
- thread t { thricky , this, n };
11365
+ thread t { tricky , this, n };
11367
11366
// ...
11368
11367
// ... should I join here? ...
11369
11368
}
@@ -11923,9 +11922,9 @@ Double-checked locking is easy to mess up.
11923
11922
11924
11923
atomic<bool> x_init;
11925
11924
11926
- if (!x_init.load(memory_order_acquire) {
11925
+ if (!x_init.load(memory_order_acquire)) {
11927
11926
lock_guard<mutex> lck(x_mutex);
11928
- if (!x_init.load(memory_order_relaxed) {
11927
+ if (!x_init.load(memory_order_relaxed)) {
11929
11928
// ... initialize x ...
11930
11929
x_init.store(true, memory_order_release);
11931
11930
}
@@ -12137,7 +12136,7 @@ C++ implementations tend to be optimized based on the assumption that exceptions
12137
12136
12138
12137
##### Example, don't
12139
12138
12140
- // don't: exception not used for error handling
12139
+ // don't: exception not used for error handling
12141
12140
int find_index(vector<string>& vec, const string& x)
12142
12141
{
12143
12142
try {
@@ -12181,7 +12180,7 @@ Not all member functions can be called.
12181
12180
##### Example
12182
12181
12183
12182
class vector { // very simplified vector of doubles
12184
- // if elem!= nullptr then elem points to sz doubles
12183
+ // if elem != nullptr then elem points to sz doubles
12185
12184
public:
12186
12185
vector() : elem{nullptr}, sz{0}{}
12187
12186
vector(int s) : elem{new double}, sz{s} { /* initialize elements */ }
@@ -12192,7 +12191,7 @@ Not all member functions can be called.
12192
12191
private:
12193
12192
owner<double*> elem;
12194
12193
int sz;
12195
- }
12194
+ };
12196
12195
12197
12196
The class invariant - here stated as a comment - is established by the constructors.
12198
12197
`new` throws if it cannot allocate the required memory.
@@ -12294,7 +12293,7 @@ One strategy is to add a `valid()` operation to every resource handle:
12294
12293
// handle error or exit
12295
12294
}
12296
12295
12297
- Ifstream fs("foo"); // not std::ifstream: valid() added
12296
+ ifstream fs("foo"); // not std::ifstream: valid() added
12298
12297
if (!fs.valid()) {
12299
12298
// handle error or exit
12300
12299
}
@@ -12370,7 +12369,7 @@ That would be a leak.
12370
12369
void leak(int x) // don't: may leak
12371
12370
{
12372
12371
auto p = new int{7};
12373
- if (x < 0) throw Get_me_out_of_here{} // may leak *p
12372
+ if (x < 0) throw Get_me_out_of_here{}; // may leak *p
12374
12373
// ...
12375
12374
delete p; // we may never get here
12376
12375
}
@@ -12387,7 +12386,7 @@ One way of avoiding such problems is to use resource handles consistently:
12387
12386
12388
12387
Another solution (often better) would be to use a local variable to eliminate explicit use of pointers:
12389
12388
12390
- void no_leak(_simplified (int x)
12389
+ void no_leak_simplified (int x)
12391
12390
{
12392
12391
vector<int> v(7);
12393
12392
// ...
@@ -12731,7 +12730,7 @@ In such cases, "crashing" is simply leaving error handling to the next level of
12731
12730
12732
12731
Most programs cannot handle memory exhaustion gracefully anyway. This is roughly equivalent to
12733
12732
12734
- void f(Int n)
12733
+ void f(int n)
12735
12734
{
12736
12735
// ...
12737
12736
p = new X[n]; // throw if memory is exhausted (by default, terminate)
@@ -13054,8 +13053,8 @@ Better performance, better compile-time checking, guaranteed compile-time evalua
13054
13053
##### Example
13055
13054
13056
13055
double x = f(2); // possible run-time evaluation
13057
- const double x = f(2); // possible run-time evaluation
13058
- constexpr double y = f(2); // error unless f(2) can be evaluated at compile time
13056
+ const double y = f(2); // possible run-time evaluation
13057
+ constexpr double z = f(2); // error unless f(2) can be evaluated at compile time
13059
13058
13060
13059
##### Note
13061
13060
@@ -16189,7 +16188,7 @@ Note that a C-style `(T)expression` cast means to perform the first of the follo
16189
16188
##### Example, bad
16190
16189
16191
16190
std::string s = "hello world";
16192
- double* p = (double*)(&s); // BAD
16191
+ double* p0 = (double*)(&s); // BAD
16193
16192
16194
16193
class base { public: virtual ~base() = 0; };
16195
16194
@@ -16202,7 +16201,7 @@ Note that a C-style `(T)expression` cast means to perform the first of the follo
16202
16201
};
16203
16202
16204
16203
derived1 d1;
16205
- base* p = &d1; // ok, implicit conversion to pointer to base is fine
16204
+ base* p1 = &d1; // ok, implicit conversion to pointer to base is fine
16206
16205
16207
16206
// BAD, tries to treat d1 as a derived2, which it is not
16208
16207
derived2* p2 = (derived2*)(p);
0 commit comments