diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md
index 5dc0684..3d8b593 100644
--- a/CppCoreGuidelines.md
+++ b/CppCoreGuidelines.md
@@ -1,6 +1,6 @@
# C++ Core Guidelines
-December 29, 2017
+January 1, 2018
Editors:
@@ -4183,7 +4183,7 @@ Flag classes declared with `struct` if there is a `private` or `protected` membe
Encapsulation.
Information hiding.
-Minimize the chance of untended access.
+Minimize the chance of unintended access.
This simplifies maintenance.
##### Example
@@ -6855,6 +6855,25 @@ Since each implementation derived from its interface as well as its implementati
As mentioned, this is just one way to construct a dual hierarchy.
+The implementation hierarchy can be used directly, rather than through the abstract interface.
+
+ void work_with_shape(Shape&);
+
+ int user()
+ {
+ Impl::Smiley my_smiley{ /* args */ }; // create concrete shape
+ // ...
+ my_smiley.some_member(); // use implementation class directly
+ // ...
+ work_with_shape(my_smiley); // use implementation through abstract interface
+ // ...
+ }
+
+This can be useful when the implementation class has members that are not offered in the abstract interface
+or if direct use of a member offers optimization opportunities (e.g., if an implementation member function is `final`)
+
+##### Note
+
Another (related) technique for separating interface and implementation is [Pimpl](#Ri-pimpl).
##### Note
@@ -10051,11 +10070,6 @@ This cannot trivially be rewritten to initialize `i` and `j` with initializers.
Note that for types with a default constructor, attempting to postpone initialization simply leads to a default initialization followed by an assignment.
A popular reason for such examples is "efficiency", but a compiler that can detect whether we made a used-before-set error can also eliminate any redundant double initialization.
-At the cost of repeating `cond` we could write:
-
- widget i = (cond) ? f1() : f3();
- widget j = (cond) ? f2() : f4();
-
Assuming that there is a logical connection between `i` and `j`, that connection should probably be expressed in code:
pair make_related_widgets(bool x)
@@ -10063,25 +10077,13 @@ Assuming that there is a logical connection between `i` and `j`, that connection
return (x) ? {f1(), f2()} : {f3(), f4() };
}
- auto init = make_related_widgets(cond);
- widget i = init.first;
- widget j = init.second;
+ auto [i, j] = make_related_widgets(cond); // C++17
-Obviously, what we really would like is a construct that initialized n variables from a `tuple`. For example:
+##### Note
- auto [i, j] = make_related_widgets(cond); // C++17, not C++14
-
-Today, we might approximate that using `tie()`:
-
- widget i; // bad: uninitialized variable
- widget j;
- tie(i, j) = make_related_widgets(cond);
-
-This may be seen as an example of the *immediately initialize from input* exception below.
-
-Creating optimal and equivalent code from all of these examples should be well within the capabilities of modern C++ compilers
-(but don't make performance claims without measuring; a compiler may very well not generate optimal code for every example and
-there may be language rules preventing some optimization that you would have liked in a particular case).
+Complex initialization has been popular with clever programmers for decades.
+It has also been a major source of errors and complexity.
+Many such errors are introduced during maintenance years after the initial implementation.
##### Example
@@ -10106,12 +10108,6 @@ The compiler will flag the uninitialized `cm3` because it is a `const`, but it w
Usually, a rare spurious member initialization is worth the absence of errors from lack of initialization and often an optimizer
can eliminate a redundant initialization (e.g., an initialization that occurs immediately before an assignment).
-##### Note
-
-Complex initialization has been popular with clever programmers for decades.
-It has also been a major source of errors and complexity.
-Many such errors are introduced during maintenance years after the initial implementation.
-
##### Exception
If you are declaring an object that is just about to be initialized from input, initializing it would cause a double initialization.
@@ -12436,6 +12432,23 @@ For example:
This invokes `istream`'s `operator bool()`.
+##### Note
+
+Explicit comparison of an integer to `0` is in general not redundant.
+The reason is that (as opposed to pointers and Booleans) an integer often has more than two reasonable values.
+Furthermore `0` (zero) is often used to indicate success.
+Consequently, it is best to be specific about the comparison.
+
+ void f(int i)
+ {
+ if (i) // suspect
+ // ...
+ if (i == success) // possibly better
+ // ...
+ }
+
+Always remember that an integer can have more that two values.
+
##### Example, bad
It has been noted that
@@ -12448,7 +12461,7 @@ Being verbose and writing
if(strcmp(p1, p2) != 0) { ... } // are the two C-style strings equal? (mistake!)
-would not save you.
+would not in itself save you.
##### Note
@@ -13124,7 +13137,82 @@ Type violations, weak types (e.g. `void*`s), and low-level code (e.g., manipulat
### Per.11: Move computation from run time to compile time
-???
+##### Reason
+
+To decrease code size and run time.
+To avoid data races by using constants.
+To catch errors at compile time (and thus eliminate the need for error-handling code).
+
+##### Example
+
+ double square(double d) { return d*d; }
+ static double s2 = square(2); // old-style: dynamic initialization
+
+ constexpr double ntimes(double d, int n) // assume 0 <= n
+ {
+ double m = 1;
+ while (n--) m *= d;
+ return m;
+ }
+ constexpr double s3 {ntimes(2, 3)}; // modern-style: compile-time initialization
+
+Code like the initialization of `s2` isn't uncommon, especially for initialization that's a bit more complicated than `square()`.
+However, compared to the initialization of `s3` there are two problems:
+
+* we suffer the overhead of a function call at run time
+* `s2` just might be accessed by another thread before the initialization happens.
+
+Note: you can't have a data race on a constant.
+
+##### Example
+
+Consider a popular technique for providing a handle for storing small objects in the handle itself and larger ones on the heap.
+
+ constexpr int on_stack_max = 20;
+
+ template
+ struct Scoped { // store a T in Scoped
+ // ...
+ T obj;
+ };
+
+ template
+ struct On_heap { // store a T on the free store
+ // ...
+ T* objp;
+ };
+
+ template
+ using Handle = typename std::conditional<(sizeof(T) <= on_stack_max),
+ Scoped, // first alternative
+ On_heap // second alternative
+ >::type;
+
+ void f()
+ {
+ Handle v1; // the double goes on the stack
+ Handle> v2; // the array goes on the free store
+ // ...
+ }
+
+Assume that `Scoped` and `On_heap` provide compatible user interfaces.
+Here we compute the optimal type to use at compile time.
+There are similar techniques for selecting the optimal function to call.
+
+##### Note
+
+The ideal is {not} to try execute everything at compile time.
+Obviously, most computations depend on inputs so they can't be moved to compile time,
+but beyond that logical constraint is the fact that complex compile-time computation can seriously increase compile times
+and complicate debugging.
+It is even possible to slow down code by compile-time computation.
+This is admittedly rare, but by factoring out a general computation into separate optimal sub-calculations it is possible to render the instruction cache less effective.
+
+##### Enforcement
+
+* Look for simple functions that might be constexpr (but are not).
+* Look for functions called with all constant-expression arguments.
+* Look for macros that could be constexpr.
### Per.12: Eliminate redundant aliases
@@ -13414,6 +13502,7 @@ Making `surface_readings` be `const` (with respect to this function) allow reaso
Immutable data can be safely and efficiently shared.
No locking is needed: You can't have a data race on a constant.
+See also [CP.mess: Message Passing](#SScp-mess) and [CP.31: prefer pass by value](#C#Rconc-data-by-value).
##### Enforcement
@@ -18584,6 +18673,13 @@ For a variable-length array, use `std::vector`, which additionally can change it
Use `gsl::span` for non-owning references into a container.
+##### Note
+
+Comparing the performance of a fixed-sized array allocated on the stack against a `vector` with its elements on the free store is bogus.
+You could just as well compare a `std::array` on the stack against the result of a `malloc()` accessed through a pointer.
+For most code, even the difference between stack allocation and free-store allocation doesn't matter, but the convenience and safety of `vector` does.
+People working with code for which that difference matters are quite capable of choosing between `array` and `vector`.
+
##### Enforcement
* Flag declaration of a C array inside a function or class that also declares an STL container (to avoid excessive noisy warnings on legacy non-STL code). To fix: At least change the C array to a `std::array`.
@@ -20317,10 +20413,6 @@ When declaring a class use the following order
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
class X {
@@ -20332,9 +20424,33 @@ Avoid multiple blocks of declarations of one access (e.g., `public`) dispersed a
// implementation details
};
-##### Note
+##### Example
-The use of macros to declare groups of members often violates any ordering rules.
+Sometimes, the default order of members conflicts with a desire to separate the public interface from implementation details.
+In such cases, private types and functions can be placed with private data.
+
+ class X {
+ public:
+ // interface
+ protected:
+ // unchecked function for use by derived class implementations
+ private:
+ // implementation details (types, functions, and data)
+ };
+
+##### Example, bad
+
+Avoid multiple blocks of declarations of one access (e.g., `public`) dispersed among blocks of declarations with different access (e.g. `private`).
+
+ class X { // bad
+ public:
+ void f();
+ public:
+ int g();
+ // ...
+ };
+
+The use of macros to declare groups of members often leads to violation of any ordering rules.
However, macros obscures what is being expressed anyway.
##### Enforcement
diff --git a/docs/gsl-intro.md b/docs/gsl-intro.md
index 25213b6..9187220 100644
--- a/docs/gsl-intro.md
+++ b/docs/gsl-intro.md
@@ -3,7 +3,7 @@
by Herb Sutter
-updated 2017-05-24
+updated 2018-01-08
## Overview: "Is this document a tutorial or a FAQ?"
@@ -59,7 +59,7 @@ dangerous_process_ints(&*remainder, v.end() - remainder); // correct but convolu
Instead, using `span` encapsulates the pointer and the length:
~~~cpp
-// BETTER: Read n contiguous ints starting at *p
+// BETTER: Read s.size() contiguous ints starting at s[0]
void process_ints(span s);
~~~
@@ -277,51 +277,12 @@ Also, `span` lets you distinguish between `.size()` and `.size_bytes()`; make
> - Prefer `span`'s `.size_bytes()` instead of `.size() * sizeof(T)`.
+## And a few `span`-related hints
-
-# *** TODO - Other span suggestions and questions back to Bjarne and Neil
+These are not directly related to `span` but can often come up while using `span`.
-Bjarne suggested:
+ * Use `byte` everywhere you are handling memory (as opposed to characters or integers). That is, when accessing a chunk of raw memory, use `gsl::span`.
-- given an STL style interface ([b:e)), how do I implement it using a span?
-
-HS: I couldn't think of an example so I skipped this
-
-- show a use of string_span
-
-HS: I think we're dropping this, so it doesn't need an example, right?
-
-- I would concentrate on span and push not_null(), narrow(), and friends to a separate note.
-
-HS: OK, stopping with the above for now -- what more can we say about span?
-
-- I would be happy to review a rough draft.
-
-HS: Here you go! :)
-
-Neil suggested:
-
-- some guidance on how to deal with standard lib container size_t vs span ptrdiff_t mismatch.
-
-HS: Do you have an example in mind?
-
-
-
-# MORE RAW NOTES
-
-I'll continue with more of these, and possibly in a separate note as Bjarne suggests a few lines above, if everyone agrees.
-
-## Neil
-
-- use `byte` everywhere you are handling memory (as opposed to characters or integers)
-
-- use `narrow()` when you cannot afford to be surprised by a value change during conversion to a smaller range (includes going between signed to unsigned)
-
-- use `narrow_cast()` when you are *sure* you won’t be surprised by a value change during conversion to a smaller range
-
-> - pass `not_null` by value
-
-I suspect this isn't right -- I think it should be "pass `not_null` the same as `T`". For example, `not_null` should be passed by value, but `not_null>` should probably be passed by `const&`.
-
-- use `not_null` on any raw pointer parameter that should never contain nullptr
+ * Use `narrow()` when you cannot afford to be surprised by a value change during conversion to a smaller range. This includes going between a signed `span` size or index and an unsigned today's-STL-container `.size()`, though the `span` constructors from containers nicely encapsulate many of these conversions.
+ * Similarly, use `narrow_cast()` when you are *sure* you won’t be surprised by a value change during conversion to a smaller range
diff --git a/scripts/hunspell/isocpp.dic b/scripts/hunspell/isocpp.dic
index f59d1bb..721e4ba 100644
--- a/scripts/hunspell/isocpp.dic
+++ b/scripts/hunspell/isocpp.dic
@@ -407,6 +407,7 @@ Productinfo
proto
ps
ptr
+ptrdiff
Ptr
ptr2
ptr's
@@ -468,6 +469,7 @@ RVO
s1
s1's
s2
+s3
Sarkar
scanf
Sd
diff --git a/scripts/python/cpplint.py b/scripts/python/cpplint.py
index 95c0c32..825c87c 100755
--- a/scripts/python/cpplint.py
+++ b/scripts/python/cpplint.py
@@ -4091,6 +4091,7 @@ def CheckTrailingSemicolon(filename, clean_lines, linenum, error):
(func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or
Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or
Search(r'\bdecltype$', line_prefix) or
+ Search(r'\breturn\s*$', line_prefix) or
Search(r'\s+=\s*$', line_prefix)):
match = None
if (match and