diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md
index 54d6498..61ea726 100644
--- a/CppCoreGuidelines.md
+++ b/CppCoreGuidelines.md
@@ -1201,6 +1201,7 @@ Interface rule summary:
* [I.24: Avoid adjacent unrelated parameters of the same type](#Ri-unrelated)
* [I.25: Prefer abstract classes as interfaces to class hierarchies](#Ri-abstract)
* [I.26: If you want a cross-compiler ABI, use a C-style subset](#Ri-abi)
+* [I.30: Encapsulate rule violations](#Ri-encapsulate)
See also
@@ -2131,6 +2132,69 @@ If you use a single compiler, you can use full C++ in interfaces. That may requi
(Not enforceable) It is difficult to reliably identify where an interface forms part of an ABI.
+### I.30: Encapsulate rule violations
+
+##### Reason
+
+To keep code simple and safe.
+Sometimes, ugly, unsafe, or error-prone techniques are necessary for logical or performance reasons.
+If so, keep them local, rather than "infecting" interfaces so that larger groups of programmers have to be aware of the
+subtleties.
+Implementation complexity should, if at all possible, not leak through interfaces into user code.
+
+##### Example
+
+Consider a program that, depending on some form of input (e.g., arguments to `main`), should consume input
+from a file, from the command line, or from standard input.
+We might write
+
+ bool owned;
+ owner inp;
+ switch (source) {
+ case std_in: owned = false; inp = &cin;
+ case command_line: owned = true; inp = new istringstream{argv[2]};
+ case file: owned = true; inp = new ifstream{argv[2]};
+ }
+ istream& in = *inp;
+
+This violated the ruly [against uninitialized variables](#Res-always),
+the rule against [ignoring ownership](#Ri-raw),
+and the rule [against magic constants](#Res-magic) .
+In particular, someone has to remember to somewhere write
+
+ if (owned) delete inp;
+
+We could handle this particular example by using `unique_ptr` with a special deleter that does nothing for `cin`,
+but that's complicated for novices (who can easily encounter this problem) and the example is an example of a more general
+problem where a property that we would like to consider static (here, ownership) needs infrequesntly be addressed
+at run time.
+The common, most frequent, and safest examples can be handled statically, so we don't want to add cost and complexity to those.
+But we must also cope with the uncommon, less-safe, and necessarily more expensive cases.
+Such examples are discussed in [[Str15]](http://www.stroustrup.com/resource-model.pdf).
+
+So, we write a class
+
+ class Istream { [[gsl::suppress(lifetime)]]
+ public:
+ enum Opt { from_line=1 };
+ Istream() { }
+ Istream(zstring p) :owned{true}, inp{new ifstream{p}} {} // read from file
+ Istream(zstring p,Opt) :owned{true}, inp{new istringstream{p}} {} // read from command line
+ ~Itream() { if (owned) delete inp; }
+ operator istream& () { return *inp; }
+ private:
+ bool owned = false;
+ istream* inp = &cin;
+ };
+
+Now, the dynamic nature of `istream` ownership has been encapsulated.
+Presumably, a bit of checking for potential errors would be added in real code.
+
+##### Enforcement
+
+* Hard, it is hard to decide what rule-breaking code is essential
+* flag rule suppression that enable rule-violations to cross interfaces
+
# F: Functions
A function specifies an action or a computation that takes the system from one consistent state to the next. It is the fundamental building block of programs.
@@ -10245,17 +10309,6 @@ It nicely encapsulates local initialization, including cleaning up scratch varia
If at all possible, reduce the conditions to a simple set of alternatives (e.g., an `enum`) and don't mix up selection and initialization.
-##### Example
-
- bool owned = false;
- owner inp = [&]{
- switch (source) {
- case default: owned = false; return &cin;
- case command_line: owned = true; return new istringstream{argv[2]};
- case file: owned = true; return new ifstream{argv[2]};
- }();
- istream& in = *inp;
-
##### Enforcement
Hard. At best a heuristic. Look for an uninitialized variable followed by a loop assigning to it.