From 148b1064da64f1f88dcc6993be9b5911af126aaa Mon Sep 17 00:00:00 2001 From: Elviss Strazdins Date: Thu, 5 Sep 2019 21:08:06 +0300 Subject: [PATCH] Correct the examples to match guideline NL.16 (#1505) --- CppCoreGuidelines.md | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index 323f92d..a63e3af 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -477,7 +477,6 @@ What is expressed in code has defined semantics and can (in principle) be checke ##### Example class Date { - // ... public: Month month() const; // do int month(); // don't @@ -4078,7 +4077,6 @@ An explicit distinction between interface and implementation improves readabilit ##### Example class Date { - // ... some representation ... public: Date(); // validate that {yy, mm, dd} is a valid date and initialize @@ -4087,6 +4085,8 @@ An explicit distinction between interface and implementation improves readabilit int day() const; Month month() const; // ... + private: + // ... some representation ... }; For example, we can now change the representation of a `Date` without affecting its users (recompilation is likely, though). @@ -5459,7 +5459,6 @@ To avoid unintended conversions. ##### Example, bad class String { - // ... public: String(int); // BAD // ... @@ -5472,7 +5471,6 @@ To avoid unintended conversions. If you really want an implicit conversion from the constructor argument type to the class type, don't use `explicit`: class Complex { - // ... public: Complex(double d); // OK: we want a conversion from d to {d, 0} // ... @@ -6101,11 +6099,11 @@ A non-throwing move will be used more efficiently by standard-library and langua template class Vector { - // ... + public: Vector(Vector&& a) noexcept :elem{a.elem}, sz{a.sz} { a.sz = 0; a.elem = nullptr; } Vector& operator=(Vector&& a) noexcept { elem = a.elem; sz = a.sz; a.sz = 0; a.elem = nullptr; } // ... - public: + private: T* elem; int sz; }; @@ -6116,11 +6114,11 @@ These operations do not throw. template class Vector2 { - // ... + public: Vector2(Vector2&& a) { *this = a; } // just use the copy Vector2& operator=(Vector2&& a) { *this = a; } // just use the copy // ... - public: + private: T* elem; int sz; }; @@ -6356,7 +6354,6 @@ A `swap` can be handy for implementing a number of idioms, from smoothly moving ##### Example, good class Foo { - // ... public: void swap(Foo& rhs) noexcept { @@ -9094,20 +9091,20 @@ The `unique_ptr` protects against leaks by guaranteeing the deletion of its obje template class X { - // ... public: T* p; // bad: it is unclear whether p is owning or not T* q; // bad: it is unclear whether q is owning or not + // ... }; We can fix that problem by making ownership explicit: template class X2 { - // ... public: owner p; // OK: p is owning T* q; // OK: q is not owning + // ... }; ##### Exception @@ -17454,7 +17451,6 @@ Flag uses where an explicitly specialized type exactly matches the types of the ##### Example class X { - // ... public: explicit X(int); X(const X&); // copy @@ -21749,7 +21745,6 @@ If you define a move constructor, you must also define a move assignment operato ##### Example class X { - // ... public: X(const X&) { /* stuff */ } @@ -21758,6 +21753,8 @@ If you define a move constructor, you must also define a move assignment operato X(x&&) noexcept { /* stuff */ } // BAD: failed to also define a move assignment operator + + // ... }; X x1; @@ -21841,10 +21838,10 @@ Prevent leaks. Leaks can lead to performance degradation, mysterious error, syst template class Vector { - // ... private: T* elem; // sz elements on the free store, owned by the class object int sz; + // ... }; This class is a resource handle. It manages the lifetime of the `T`s. To do so, `Vector` must define or delete [the set of special operations](???) (constructors, a destructor, etc.).