@@ -3524,7 +3524,6 @@ but:
35243524 int y;
35253525 Month m;
35263526 char d; // day
3527- Date(int yy, Month mm, char dd);
35283527 };
35293528
35303529##### Note
@@ -4169,7 +4168,7 @@ Note that if you define a destructor, you must define or delete [all default ope
41694168 ~Smart_ptr2() { delete p; } // p is an owner!
41704169 };
41714170
4172- void use(Smart_ptr <int> p1)
4171+ void use(Smart_ptr2 <int> p1)
41734172 {
41744173 auto p2 = p1; // error: double deletion
41754174 }
@@ -4279,7 +4278,7 @@ See [this in the Discussion section](#Sd-dtor).
42794278##### Example, bad
42804279
42814280 struct Base { // BAD: no virtual destructor
4282- virtual f();
4281+ virtual void f();
42834282 };
42844283
42854284 struct D : Base {
@@ -4440,8 +4439,8 @@ The C++11 initializer list rule eliminates the need for many constructors. For e
44404439 Rec2(const string& ss, int ii = 0) :s{ss}, i{ii} {} // redundant
44414440 };
44424441
4443- Rec r1 {"Foo", 7};
4444- Rec r2 {"Bar"};
4442+ Rec2 r1 {"Foo", 7};
4443+ Rec2 r2 {"Bar"};
44454444
44464445The `Rec2` constructor is redundant.
44474446Also, 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.
45324531 // ...
45334532 }
45344533
4535- void is_valid() { return valid; }
4534+ bool is_valid() { return valid; }
45364535 void read(); // read from f
45374536 // ...
45384537 };
@@ -4542,7 +4541,7 @@ Leaving behind an invalid object is asking for trouble.
45424541 X3 file {"Heraclides"};
45434542 file.read(); // crash or bad read!
45444543 // ...
4545- if (is_valid()) {
4544+ if (file. is_valid()) {
45464545 file.read();
45474546 // ...
45484547 }
@@ -4619,7 +4618,7 @@ A class with members that all have default constructors implicitly gets a defaul
46194618
46204619 struct X {
46214620 string s;
4622- vector v;
4621+ vector<int> v;
46234622 };
46244623
46254624 X x; // means X{{}, {}}; that is the empty string and the empty vector
@@ -4945,7 +4944,7 @@ To avoid repetition and accidental differences.
49454944 int y;
49464945 public:
49474946 Date(int ii, Month mm, year yy)
4948- :i{ii}, m{mm} y{yy}
4947+ :i{ii}, m{mm}, y{yy}
49494948 { if (!valid(i, m, y)) throw Bad_date{}; }
49504949
49514950 Date(int ii, Month mm)
@@ -4964,7 +4963,7 @@ The common action gets tedious to write and may accidentally not be common.
49644963 int y;
49654964 public:
49664965 Date2(int ii, Month mm, year yy)
4967- :i{ii}, m{mm} y{yy}
4966+ :i{ii}, m{mm}, y{yy}
49684967 { if (!valid(i, m, y)) throw Bad_date{}; }
49694968
49704969 Date2(int ii, Month mm)
@@ -5476,9 +5475,9 @@ Because we defined the destructor, we must define the copy and move operations.
54765475 ~Tracer2() { cerr << "exiting " << message << '\n'; }
54775476
54785477 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; }
54805479 Tracer2(Tracer2&& a) :message{a.message} {}
5481- Tracer2& operator=(Tracer2&& a) { message = a.message; }
5480+ Tracer2& operator=(Tracer2&& a) { message = a.message; return *this; }
54825481 };
54835482
54845483Writing 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
62316230
62326231
62336232 class Impl::Circle : public Circle, public Impl::Shape { // implementation
6234- publc :
6233+ public :
62356234 // constructors, destructor
62366235
62376236 int radius() { /* ... */ }
@@ -6246,7 +6245,7 @@ And we could extend the hierarchies by adding a Smiley class (:-)):
62466245 };
62476246
62486247 class Impl::Smiley : Public Smiley, public Impl::Circle { // implementation
6249- publc :
6248+ public :
62506249 // constructors, destructor
62516250 // ...
62526251 }
@@ -7105,7 +7104,7 @@ Avoiding inconsistent definition in different namespaces
71057104 bool operator==(S, S); // OK: in the same namespace as S, and even next to S
71067105 S s;
71077106
7108- bool s == s;
7107+ bool x = ( s == s) ;
71097108
71107109This is what a default `==` would do, if we had such defaults.
71117110
@@ -7118,7 +7117,7 @@ This is what a default `==` would do, if we had such defaults.
71187117
71197118 N::S s;
71207119
7121- bool s == s; // finds N::operator==() by ADL
7120+ bool x = ( s == s) ; // finds N::operator==() by ADL
71227121
71237122##### Example, bad
71247123
@@ -7456,7 +7455,7 @@ If you can't name an enumeration, the values are not related
74567455
74577456##### Example, bad
74587457
7459- enum { red = 0xFF0000, scale = 4, signed = 1 };
7458+ enum { red = 0xFF0000, scale = 4, is_signed = 1 };
74607459
74617460Such code is not uncommon in code written before there were convenient alternative ways of specifying integer constants.
74627461
@@ -7466,7 +7465,7 @@ Use `constexpr` values instead. For example:
74667465
74677466 constexpr int red = 0xFF0000;
74687467 constexpr short scale = 4;
7469- constexpr bool signed = true;
7468+ constexpr bool is_signed = true;
74707469
74717470##### Enforcement
74727471
@@ -7519,8 +7518,8 @@ The default gives a consecutive set of values that is good for `switch`-statemen
75197518##### Example
75207519
75217520 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,
75247523 jul, august, sep, oct, nov, dec }; // starting with 1 is conventional
75257524 enum class Base_flag { dec = 1, oct = dec << 1, hex = dec << 2 }; // set of bits
75267525
@@ -8533,7 +8532,7 @@ The more traditional and lower-level near-equivalent is longer, messier, harder
85338532 is.read(s, maxstring);
85348533 res[elemcount++] = s;
85358534 }
8536- nread = elemcount;
8535+ nread = & elemcount;
85378536 return res;
85388537 }
85398538
@@ -11114,7 +11113,7 @@ Avoids nasty errors from unreleased locks.
1111411113
1111511114Sooner or later, someone will forget the `mtx.unlock()`, place a `return` in the `... do stuff ...`, throw an exception, or something.
1111611115
11117- mutex mtx;
11116+ mutex mtx;
1111811117
1111911118 void do_stuff()
1112011119 {
@@ -11363,7 +11362,7 @@ The plain `thread`s should be assumed to use the full generality of `std::thread
1136311362
1136411363 void use(int n)
1136511364 {
11366- thread t { thricky , this, n };
11365+ thread t { tricky , this, n };
1136711366 // ...
1136811367 // ... should I join here? ...
1136911368 }
@@ -11923,9 +11922,9 @@ Double-checked locking is easy to mess up.
1192311922
1192411923 atomic<bool> x_init;
1192511924
11926- if (!x_init.load(memory_order_acquire) {
11925+ if (!x_init.load(memory_order_acquire)) {
1192711926 lock_guard<mutex> lck(x_mutex);
11928- if (!x_init.load(memory_order_relaxed) {
11927+ if (!x_init.load(memory_order_relaxed)) {
1192911928 // ... initialize x ...
1193011929 x_init.store(true, memory_order_release);
1193111930 }
@@ -12137,7 +12136,7 @@ C++ implementations tend to be optimized based on the assumption that exceptions
1213712136
1213812137##### Example, don't
1213912138
12140- // don't: exception not used for error handling
12139+ // don't: exception not used for error handling
1214112140 int find_index(vector<string>& vec, const string& x)
1214212141 {
1214312142 try {
@@ -12181,7 +12180,7 @@ Not all member functions can be called.
1218112180##### Example
1218212181
1218312182 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
1218512184 public:
1218612185 vector() : elem{nullptr}, sz{0}{}
1218712186 vector(int s) : elem{new double}, sz{s} { /* initialize elements */ }
@@ -12192,7 +12191,7 @@ Not all member functions can be called.
1219212191 private:
1219312192 owner<double*> elem;
1219412193 int sz;
12195- }
12194+ };
1219612195
1219712196The class invariant - here stated as a comment - is established by the constructors.
1219812197`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:
1229412293 // handle error or exit
1229512294 }
1229612295
12297- Ifstream fs("foo"); // not std::ifstream: valid() added
12296+ ifstream fs("foo"); // not std::ifstream: valid() added
1229812297 if (!fs.valid()) {
1229912298 // handle error or exit
1230012299 }
@@ -12370,7 +12369,7 @@ That would be a leak.
1237012369 void leak(int x) // don't: may leak
1237112370 {
1237212371 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
1237412373 // ...
1237512374 delete p; // we may never get here
1237612375 }
@@ -12387,7 +12386,7 @@ One way of avoiding such problems is to use resource handles consistently:
1238712386
1238812387Another solution (often better) would be to use a local variable to eliminate explicit use of pointers:
1238912388
12390- void no_leak(_simplified (int x)
12389+ void no_leak_simplified (int x)
1239112390 {
1239212391 vector<int> v(7);
1239312392 // ...
@@ -12731,7 +12730,7 @@ In such cases, "crashing" is simply leaving error handling to the next level of
1273112730
1273212731Most programs cannot handle memory exhaustion gracefully anyway. This is roughly equivalent to
1273312732
12734- void f(Int n)
12733+ void f(int n)
1273512734 {
1273612735 // ...
1273712736 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
1305413053##### Example
1305513054
1305613055 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
1305913058
1306013059##### Note
1306113060
@@ -16189,7 +16188,7 @@ Note that a C-style `(T)expression` cast means to perform the first of the follo
1618916188##### Example, bad
1619016189
1619116190 std::string s = "hello world";
16192- double* p = (double*)(&s); // BAD
16191+ double* p0 = (double*)(&s); // BAD
1619316192
1619416193 class base { public: virtual ~base() = 0; };
1619516194
@@ -16202,7 +16201,7 @@ Note that a C-style `(T)expression` cast means to perform the first of the follo
1620216201 };
1620316202
1620416203 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
1620616205
1620716206 // BAD, tries to treat d1 as a derived2, which it is not
1620816207 derived2* p2 = (derived2*)(p);
0 commit comments