From 6a39167b8661ab5f2dcfd0a78a4d3800785b3f58 Mon Sep 17 00:00:00 2001 From: Dima Date: Wed, 6 Jan 2016 22:31:13 -0800 Subject: [PATCH 1/7] Declaring one name per declaration. --- CppCoreGuidelines.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index 2e9766c..f440203 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -7880,9 +7880,10 @@ The *always initialize* rule is a style rule aimed to improve maintainability as Here is an example that is often considered to demonstrate the need for a more relaxed rule for initialization - widget i, j; // "widget" a type that's expensive to initialize, possibly a large POD + widget i; // "widget" a type that's expensive to initialize, possibly a large POD + widget j; - if (cond) { // bad: i and j are initialized "late" + if (cond) { // bad: i and j are initialized "late" i = f1(); j = f2(); } From 7ae316c605ee9e37d06aebf07663216254dce9c9 Mon Sep 17 00:00:00 2001 From: Dima Date: Wed, 6 Jan 2016 23:20:52 -0800 Subject: [PATCH 2/7] Minor grammar fix. --- CppCoreGuidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index f440203..38c7fa3 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -8718,7 +8718,7 @@ Readability. ##### Enforcement -Flag empty statements that are not blocks and doesn't "contain" comments. +Flag empty statements that are not blocks and don't "contain" comments. ### ES.86: Avoid modifying loop control variables inside the body of raw for-loops From 2d9c0582ada1e30557afac244d59f43dc267b7a1 Mon Sep 17 00:00:00 2001 From: Dima Date: Wed, 6 Jan 2016 23:23:30 -0800 Subject: [PATCH 3/7] Another minor grammar fix. --- CppCoreGuidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index 38c7fa3..64026c7 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -9080,7 +9080,7 @@ Flag `const_cast`s. ##### Reason -Constructs that cannot overflow, don't, and usually runs faster: +Constructs that cannot overflow, don't, and usually run faster: ##### Example From 20ed3d12fd90daaab7e3482b5931796cccec567c Mon Sep 17 00:00:00 2001 From: Titus Winters Date: Tue, 12 Jan 2016 13:28:08 -0500 Subject: [PATCH 4/7] Editorial changes for PER, CP, E, and T. --- CppCoreGuidelines.md | 45 ++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index 0ae6a6a..cae471e 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -9616,7 +9616,7 @@ See also: It is hard to be certain that concurrency isn't used now or sometime in the future. Code gets re-used. -Libraries using threads my be used from some other part of the program. +Libraries using threads may be used from some other part of the program. Note that this applies most urgently to library code and least urgently to stand-alone applications. ##### Example @@ -9649,7 +9649,7 @@ There are several ways that this example could be made safe for a multi-threaded However, there are also many examples where code that was "known" to never run in a multi-threaded program was run as part of a multi-threaded program. Often years later. Typically, such programs lead to a painful effort to remove data races. -Therefore, code that is never intended to run in a multi-threaded environment should be clearly labeled as such. +Therefore, code that is never intended to run in a multi-threaded environment should be clearly labeled as such and ideally come with compile or run-time enforcement mechanisms to catch those usage bugs early. ### CP.2: Avoid data races @@ -9735,7 +9735,7 @@ Error handling involves: * Preserve the state of a program in a valid state * Avoid resource leaks -It is not possible to recover from all errors. If recovery from an error is not possible, it is important to quickly "get out" in a well-defined way. A strategy for error handling must be simple, or it becomes a source of even worse errors. +It is not possible to recover from all errors. If recovery from an error is not possible, it is important to quickly "get out" in a well-defined way. A strategy for error handling must be simple, or it becomes a source of even worse errors. Untested and rarely executed error-handling code is itself the source of many bugs. The rules are designed to help avoid several kinds of errors: @@ -9861,7 +9861,7 @@ There is nothing exceptional about finding a value in a `vector`. ##### Reason -To use an objects it must be in a valid state (defined formally or informally by an invariant) and to recover from an error every object not destroyed must be in a valid state. +To use an object it must be in a valid state (defined formally or informally by an invariant) and to recover from an error every object not destroyed must be in a valid state. ##### Note @@ -9872,7 +9872,7 @@ An [invariant](#Rc-struct) is logical condition for the members of an object tha ##### Reason Leaving an object without its invariant established is asking for trouble. -Not all member function can be called. +Not all member functions can be called. ##### Example @@ -9917,7 +9917,7 @@ This is verbose. In larger code with multiple possible `throw`s explicit release void f3(int i) // OK: resource management done by a handle { - auto p = make_unique(); + auto p = make_unique(12); // ... if (i < 17) throw Bad {"in f()", i}; // ... @@ -9927,7 +9927,7 @@ Note that this works even when the `throw` is implicit because it happened in a void f4(int i) // OK: resource management done by a handle { - auto p = make_unique(); + auto p = make_unique(12); // ... helper(i); // may throw // ... @@ -9954,12 +9954,12 @@ First challenge that assumption; there are many anti-exceptions myths around. We know of only a few good reasons: * We are on a system so small that the exception support would eat up most of our 2K or memory. -* We are in a hard-real-time system and we don't have tools that allows us that an exception is handled within the required time. +* We are in a hard-real-time system and we don't have tools that guarantee us that an exception is handled within the required time. * We are in a system with tons of legacy code using lots of pointers in difficult-to-understand ways (in particular without a recognizable ownership strategy) so that exceptions could cause leaks. * We get fired if we challenge our manager's ancient wisdom. -Only the first of these reasons is fundamental, so whenever possible, use exception to implement RAII. +Only the first of these reasons is fundamental, so whenever possible, use exceptions to implement RAII, or design your RAII objects to never fail. When exceptions cannot be used, simulate RAII. That is, systematically check that objects are valid after construction and still release all resources in the destructor. One strategy is to add a `valid()` operation to every resource handle: @@ -10031,7 +10031,7 @@ Many standard library functions are `noexcept` including all the standard librar // ... do something ... } -The `noexcept` here states that I am not willing or able to handle the situation where I cannot construct the local `vector`. That is, I consider memory exhaustion a serious design error (on line with hardware failures) so that I'm willing to crash the program if it happens. +The `noexcept` here states that I am not willing or able to handle the situation where I cannot construct the local `vector`. That is, I consider memory exhaustion a serious design error (on par with hardware failures) so that I'm willing to crash the program if it happens. **See also**: [discussion](#Sd-noexcept). @@ -10164,7 +10164,7 @@ Instead, use: ##### Enforcement -Flag by-value exceptions if their type are part of a hierarchy (could require whole-program analysis to be perfect). +Flag by-value exceptions if their types are part of a hierarchy (could require whole-program analysis to be perfect). ### E.16: Destructors, deallocation, and `swap` must never fail @@ -10186,7 +10186,7 @@ We don't know how to write reliable programs if a destructor, a swap, or a memor ##### Note -Many have tried to write reliable code violating this rule for examples such as a network connection that "refuses to close". To the best of our knowledge nobody has found a general way of doing this though occasionally, for very specific examples, you can get away with setting some state for future cleanup. Every example, we have seen of this is error-prone, specialized, and usually buggy. +Many have tried to write reliable code violating this rule for examples such as a network connection that "refuses to close". To the best of our knowledge nobody has found a general way of doing this though occasionally, for very specific examples, you can get away with setting some state for future cleanup. Every example we have seen of this is error-prone, specialized, and usually buggy. ##### Note @@ -10194,7 +10194,7 @@ The standard library assumes that destructors, deallocation functions (e.g., `op ##### Note -Deallocation functions, including `operator delete`, must be `noexcept`. `swap` functions must be `noexcept`. Most destructors are implicitly `noexcept` by default. destructors, make them `noexcept`. +Deallocation functions, including `operator delete`, must be `noexcept`. `swap` functions must be `noexcept`. Most destructors are implicitly `noexcept` by default. ##### Enforcement @@ -10268,7 +10268,7 @@ Let cleanup actions on the unwinding path be handled by [RAII](#Re-raii). # Con: Constants and Immutability You can't have a race condition on a constant. -it is easier to reason about a program when many of the objects cannot change their values. +It is easier to reason about a program when many of the objects cannot change their values. Interfaces that promises "no change" of objects passed as arguments greatly increase readability. Constant rule summary: @@ -10362,6 +10362,10 @@ This gives a more precise statement of design intent, better readability, more e ??? +##### Note + +See F.4. + ##### Enforcement ??? @@ -10749,7 +10753,7 @@ It is better and simpler just to use `Sortable`: ##### Note -The set of "standard" concepts is evolving as we approaches real (ISO) standardization. +The set of "standard" concepts is evolving as we approach real (ISO) standardization. ##### Note @@ -10900,7 +10904,7 @@ Examples of complete sets are ##### Reason A meaningful/useful concept has a semantic meaning. -Expressing this semantics in a informal, semi-formal, or formal way makes the concept comprehensible to readers and the effort to express it can catch conceptual errors. +Expressing these semantics in an informal, semi-formal, or formal way makes the concept comprehensible to readers and the effort to express it can catch conceptual errors. Specifying semantics is a powerful design tool. ##### Example @@ -11065,7 +11069,7 @@ Conversions are taken into account. You don't have to remember the names of all ##### Reason Function objects can carry more information through an interface than a "plain" pointer to function. -In general, passing function objects give better performance than passing pointers to functions. +In general, passing function objects gives better performance than passing pointers to functions. ##### Example @@ -11136,7 +11140,7 @@ This saves the user of `Matrix` from having to know that its elements are stored ##### Example template - using Value_type = container_traits::value_type; + using Value_type = typename container_traits::value_type; This saves the user of `Value_type` from having to know the technique used to implement `value_type`s. @@ -11497,7 +11501,7 @@ There are three major ways to let calling code customize a template. Templates are the backbone of C++'s support for generic programming and class hierarchies the backbone of its support for object-oriented programming. -The two language mechanisms can be use effectively in combination, but a few design pitfalls must be avoided. +The two language mechanisms can be used effectively in combination, but a few design pitfalls must be avoided. ### T.80: Do not naively templatize a class hierarchy @@ -11917,7 +11921,8 @@ That makes the code concise and gives better locality than alternatives. ##### Example - ??? for-loop equivalent + auto earlyUsersEnd = std::remove_if(users.begin(), users.end(), + [](const User &a) { return a.id > 100; }); **Exception**: Naming a lambda can be useful for clarity even if it is used only once From 67bf6a14ab4ef2dbd9e16c0e4676f0860596ccf0 Mon Sep 17 00:00:00 2001 From: ZhangWangda Date: Tue, 26 Jan 2016 14:20:38 -0500 Subject: [PATCH 5/7] fix typo add a missing bracket --- CppCoreGuidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index 2acddd1..6b78415 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -2623,7 +2623,7 @@ A `span` represents a range of elements, but how do we manipulate elements of th for (int x : s) cout << x << '\n'; // range traversal (guaranteed correct) for (int i = 0; i Date: Wed, 27 Jan 2016 16:39:09 -0200 Subject: [PATCH 6/7] passes -> passed --- CppCoreGuidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index 2acddd1..dc38aea 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -9324,7 +9324,7 @@ also define an overload that takes lvalues. void print(const string& s); // print and preserve the value of s An rvalue can be assumed not to be accessed after being passed. -An lvalue must in general be assumed to be used again after being passes, that is after a `std::move`, +An lvalue must in general be assumed to be used again after being passed, that is after a `std::move`, so "careful programming" is essential to avoid disasters -- better not rely on that. ###### Note From ad97ba3fdb3bc454eda59581e04ad744f8109fdd Mon Sep 17 00:00:00 2001 From: Bjarne Stroustrup Date: Mon, 1 Feb 2016 16:19:39 -0500 Subject: [PATCH 7/7] Dealt with issue 516 added C.8 and C.9 to clarify access conventions --- CppCoreGuidelines.md | 95 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index 72ccddc..63e9b54 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -3216,6 +3216,8 @@ Class rule summary: * [C.4: Make a function a member only if it needs direct access to the representation of a class](#Rc-member) * [C.5: Place helper functions in the same namespace as the class they support](#Rc-helper) * [C.7: Don't define a class or enum and declare a variable of its type in the same statement](#Rc-standalone) +* [C.8: use `class` rather that `struct` if any member is non-public](#Rc-class) +* [C.9: minimize exposure of members](#Rc-private) Subsections: @@ -3254,11 +3256,18 @@ Probably impossible. Maybe a heuristic looking for data items used together is p ##### Reason -Ease of comprehension. The use of `class` alerts the programmer to the need for an invariant. +Readability. +Ease of comprehension. +The use of `class` alerts the programmer to the need for an invariant. +This is a useful convention. ##### Note -An invariant is a logical condition for the members of an object that a constructor must establish for the public member functions to assume. After the invariant is established (typically by a constructor) every member function can be called for the object. An invariant can be stated informally (e.g., in a comment) or more formally using `Expects`. +An invariant is a logical condition for the members of an object that a constructor must establish for the public member functions to assume. +After the invariant is established (typically by a constructor) every member function can be called for the object. +An invariant can be stated informally (e.g., in a comment) or more formally using `Expects`. + +If all data members can vary independently of each other, no invariant is possible. ##### Example @@ -3270,14 +3279,25 @@ An invariant is a logical condition for the members of an object that a construc but: class Date { + public: + Date(int yy, Month mm, char dd); // validate that {yy, mm, dd} is a valid date and initialize + // ... private: int y; Month m; char d; // day - public: - Date(int yy, Month mm, char dd); // validate that {yy, mm, dd} is a valid date and initialize - // ... }; + +##### Note + +If a class has any `private` data, a user cannot completely initialize an object without the use of a constructor. +Hence, the class definer will provide a constructor and must specify its meaning. +This effectivily means the definer need to define an invariant. + +* See also [define a class with private data as `class`](#Rc-class). +* See also [Prefer to place the interface first in a class](#Rl-order). +* See also [minimize exposure of members](#Rc-private). +* See also [Avoid `protected` data](#Rh-protected). ##### Enforcement @@ -3387,6 +3407,63 @@ Mixing a type definition and the definition of another entity in the same declar * Flag if the `}` of a class or enumeration definition is not followed by a `;`. The `;` is missing. +### C.8: use `class` rather that `struct` if any member is non-public + +##### Reason + +Readability. +To make it clear that something is being hidden/abstracted. +This is a useful convention. + +##### Example, bad + + struct Date { + int d,m; + + Date(int i, Month m); + // ... lots of functions ... + private: + int y; // year + }; + +There is nothing wrong with this code as far as the C++ language rules are concerned, +but nearly everything is wrong from a design perspective. +The private data is hidden far from the public data. +The data is split in different parts of the class declaration. +Different parts of the data has difference access. +All of this decreases readability and complicates maintenance. + + +##### Note + +Prefer to place the interface first in a class [see](#Rl-order). + +##### Enforcement + +Flag classes declarate with `struct` if there is a `private` or `public` member. + + +### C.9: minimize exposure of members + +##### Reason + +Encapsulation. +Information hiding. +Mimimize the chance of untended access. +This simplifies maintenance. + +##### Example + + ??? + +##### Note + +Prefer the order `public` members before `protected` members before `private` members [see](#Rl-order). + +##### Enforcement + +??? + ## C.concrete: Concrete types One ideal for a class is to be a regular type. @@ -5495,7 +5572,6 @@ Designing rules for classes in a hierarchy summary: * [C.128: Use `override` to make overriding explicit in large class hierarchies](#Rh-override) * [C.129: When designing a class hierarchy, distinguish between implementation inheritance and interface inheritance](#Rh-kind) * [C.130: Redefine or prohibit copying for a base class; prefer a virtual `clone` function instead](#Rh-copy) - * [C.131: Avoid trivial getters and setters](#Rh-get) * [C.132: Don't make a function `virtual` without reason](#Rh-virtual) * [C.133: Avoid `protected` data](#Rh-protected) @@ -13892,10 +13968,17 @@ Use the `public` before `protected` before `private` order. Private types and functions can be placed with private data. +Avoid multiple blocks of declarations of one access (e.g., `public`) dispersed among blocks of declarations with different access (e.g. `private`). + ##### Example ??? +##### Note + +The use of macros to declare groups of members often violates any ordering rules. +However, macros obscures what is being expressed anyway. + ##### Enforcement Flag departures from the suggested order. There will be a lot of old code that doesn't follow this rule.