mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2024-03-22 13:30:58 +08:00
minor improvements to SL.io
This commit is contained in:
parent
c99a366bba
commit
046d62c51e
|
@ -1,6 +1,6 @@
|
||||||
# <a name="main"></a>C++ Core Guidelines
|
# <a name="main"></a>C++ Core Guidelines
|
||||||
|
|
||||||
April 22, 2017
|
April 24, 2017
|
||||||
|
|
||||||
|
|
||||||
Editors:
|
Editors:
|
||||||
|
@ -589,7 +589,7 @@ Better:
|
||||||
|
|
||||||
Now, there is no explicit mention of the iteration mechanism, and the loop operates on a reference to `const` elements so that accidental modification cannot happen. If modification is desired, say so:
|
Now, there is no explicit mention of the iteration mechanism, and the loop operates on a reference to `const` elements so that accidental modification cannot happen. If modification is desired, say so:
|
||||||
|
|
||||||
for (auto& x : v) { /* modify x */ }
|
for (auto& x : v) { /* do to with x */ }
|
||||||
|
|
||||||
Sometimes better still, use a named algorithm:
|
Sometimes better still, use a named algorithm:
|
||||||
|
|
||||||
|
@ -4048,17 +4048,17 @@ For example:
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
If the set of direct users of a set of variables cannot be easily determined, the type or usage of that set cannot be (easily) changed/improved.
|
If the set of direct users of a set of variables cannot be easily determined, the type or usage of that set cannot be (easily) changed/improved.
|
||||||
For `public` and `protected` data, that's usually the case.
|
For `public`and `protected` data, that's usually the case.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
A class can provide two interfaces to its users.
|
A class can provide two interfaces to its users.
|
||||||
One for derived classes (`protected`) and one for general users (`public`).
|
One for derived classes (`protected`) and one for general users (`public`).
|
||||||
For example, a derived class might be allowed to skip a run-time check because it has already guaranteed correctness:
|
For example, a derived class might be allowed to skip a run-time check because it has already guarenteed correctness:
|
||||||
|
|
||||||
class Foo {
|
class Foo {
|
||||||
public:
|
public:
|
||||||
int bar(int x) { check(x); return do_bar(); }
|
int bar(int x) { check(x); return do_bar(); }
|
||||||
// ...
|
// ...
|
||||||
protected:
|
protected:
|
||||||
int do_bar(int x); // do some operation on the data
|
int do_bar(int x); // do some operation on the data
|
||||||
|
@ -4069,16 +4069,12 @@ For example, a derived class might be allowed to skip a run-time check because i
|
||||||
|
|
||||||
class Dir : public Foo {
|
class Dir : public Foo {
|
||||||
//...
|
//...
|
||||||
int mem(int x, int y)
|
int mem(int x, int y) { /* ... do something ... */ rteurn do_bar(x+y); } // OK: derived class can bypass check
|
||||||
{
|
|
||||||
/* ... do something ... */
|
|
||||||
return do_bar(x+y); // OK: derived class can bypass check
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void user(Foo& x)
|
void user(Foo& x)
|
||||||
{
|
{
|
||||||
int r1 = x.bar(1); // OK, will check
|
int r1 = x.bar(1); // OK, will check
|
||||||
int r2 = x.do_bar(2); // error: would bypass check
|
int r2 = x.do_bar(2); // error: would bypass check
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
@ -6821,14 +6817,14 @@ This kind of "vector" isn't meant to be used as a base class at all.
|
||||||
Style st;
|
Style st;
|
||||||
};
|
};
|
||||||
|
|
||||||
Now it is up to every derived `Shape` to manipulate the protected data correctly.
|
Now it is up to every defived `Shape` to manipulate the protected data correctly.
|
||||||
This has been popular, but also a major source of maintenance problems.
|
This has been popular, but also a major source of maintenance problems.
|
||||||
In a large class hierarchy, the consistent use of protected data is hard to maintain because there can be a lot of code,
|
In a large class hierarchy, the consistent use of protected data is hard to maintain because there can be a lot of code,
|
||||||
spread over a lot of classes.
|
spread over a lot of classes.
|
||||||
The set of classes that can touch that data is open: anyone can derive a new class and start manipulating the protected data.
|
The set of classes that can touch that data is open: anyone can derive a new class and start manipulating the protected data.
|
||||||
Often, it is not possible to examine the complete set of classes so any change to the representation of the class becomes infeasible.
|
Often, it is not possible to examine the complete set of classes so any change to the representation of the class becomes infeasible.
|
||||||
There is no enforced invariant for the protected data; it is much like a set of global variables.
|
There is no enforced invariant for the protected data; it is much like a set of global variables.
|
||||||
The protected data has de facto become global to a large body of code.
|
The protected data has de-factor become global to a large body of code.
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
|
@ -6964,18 +6960,18 @@ or various bases from boost.intrusive (e.g. `list_base_hook` or `intrusive_ref_c
|
||||||
};
|
};
|
||||||
|
|
||||||
class Derive1 : public Interface, virtual protected Utility {
|
class Derive1 : public Interface, virtual protected Utility {
|
||||||
// override Interface functions
|
// overrride Iterface functions
|
||||||
// Maybe override Utility virtual functions
|
// Maybe override Utility virtual functions
|
||||||
// ...
|
// ...
|
||||||
};
|
};
|
||||||
|
|
||||||
class Derive2 : public Interface, virtual protected Utility {
|
class Derive2 : public Interface, virtual protected Utility {
|
||||||
// override Interface functions
|
// overrride Iterface functions
|
||||||
// Maybe override Utility virtual functions
|
// Maybe override Utility virtual functions
|
||||||
// ...
|
// ...
|
||||||
};
|
};
|
||||||
|
|
||||||
Factoring out `Utility` makes sense if many derived classes share significant "implementation details."
|
Factoring out `Utility` makes sense if many derived classes share significent "implementation details."
|
||||||
|
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
@ -6986,7 +6982,7 @@ and `Utility` is the root of an [implementation hierarchy](Rh-kind).
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
Often, linearization of a hierarchy is a better solution.
|
Often, lineraization of a hierarchy is a better solution.
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
|
|
||||||
|
@ -14510,33 +14506,33 @@ Awkward.
|
||||||
|
|
||||||
##### Reason
|
##### Reason
|
||||||
|
|
||||||
Exception specifications make error handling brittle, impose a run-time cost, and have been deprecated from the C++ standard.
|
Exception specifications make error handling brittle, impose a run-time cost, and have been removed from the C++ standard.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
int use(int arg)
|
int use(int arg)
|
||||||
throw(X, Y)
|
throw(X,Y)
|
||||||
{
|
{
|
||||||
// ...
|
// ...
|
||||||
auto x = f(arg);
|
auto x = f(arg);
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
if `f()` throws an exception different from `X` and `Y` the unexpected handler is invoked, which by default terminates.
|
if 'f()' throws an exception different from `X` and `Y` the unexpected handler is invoked, which by default terminates.
|
||||||
That's OK, but say that we have checked that this cannot happen and `f` is changed to throw a new exception `Z`,
|
That's OK, but say that we have checked that this cannot happen and `f` is changed to throw a new exception `Z`,
|
||||||
we now have a crash on our hands unless we change `use()` (and re-test everything).
|
we now have a crash on our hands unless we change `use()` (and re-test everything).
|
||||||
The snag is that `f()` may be in a library we do not control and the new exception is not anything that `use()` can do
|
The snag is that `f()` may be in a library we do not control and the new exception is not anything that `use()` can do
|
||||||
anything about or is in any way interested in.
|
anything about or is in any way interested in.
|
||||||
We can change `use()` to pass `Z` through, but now `use()`'s callers probably needs to be modified.
|
We can change `use()` to pass `Z` through, but now `use()`'s callers probably needs to be modified.
|
||||||
This quickly becomes unmanageable.
|
This quickly becomes unmanageable.
|
||||||
Alternatively, we can add a `try`-`catch` to `use()` to map `Z` into an acceptable exception.
|
Alternatively, we can add a `try`-`catch` to `use()` to map `Z` into an acceptable excption.
|
||||||
This too, quickly becomes unmanageable.
|
This too, quickly becomes unmanageable.
|
||||||
Note that changes to the set of exceptions often happens at the lowest level of a system
|
Note that changes to the set of exceptions often happens at the lowest level of a system
|
||||||
(e.g., because of changes to a network library or some middleware), so changes "bubble up" through long call chains.
|
(e.g., because of changes to a network library or some middleware), so changes "bubble up" through long call chains.
|
||||||
In a large code base, this could mean that nobody could update to a new version of a library until the last user was modified.
|
In a large code base, this could mean that nobody could update to a new version of a library until the last user was modified.
|
||||||
If `use()` is part of a library, it may not be possible to update it because a change could affect unknown clients.
|
If `use()` is part of a library, it may not be possible to update it bacause a change could affect unknow clients.
|
||||||
|
|
||||||
The policy of letting exceptions propagate until they reach a function that potentially can handle it has proven itself over the years.
|
The policy of letting exceptions propogate until they reach a function that potentially can handle it has proven itself over the years.
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
|
@ -14545,7 +14541,7 @@ For example, see [Stroustrup94](#Stroustrup94).
|
||||||
|
|
||||||
##### Note
|
##### Note
|
||||||
|
|
||||||
If no exception may be thrown, use [`noexcept`](#Re-noexcept)
|
If no exception may be throw, use [`noexcept`](#Re-noexcept) or its equivalent `throw()`.
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
|
|
||||||
|
@ -17391,7 +17387,7 @@ It is more likely to be stable, well-maintained, and widely available than your
|
||||||
##### Reason
|
##### Reason
|
||||||
|
|
||||||
Adding to `std` may change the meaning of otherwise standards conforming code.
|
Adding to `std` may change the meaning of otherwise standards conforming code.
|
||||||
Additions to `std` may clash with future versions of the standard.
|
Additions to `std` may clash with furture versions of the standard.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
|
@ -17740,7 +17736,10 @@ C++17
|
||||||
|
|
||||||
## <a name="SS-io"></a>SL.io: Iostream
|
## <a name="SS-io"></a>SL.io: Iostream
|
||||||
|
|
||||||
???
|
`iostream`s is a type safe, extensible, formatted and unformatted I/O library for streaming I/O.
|
||||||
|
It supports multiple (and user extensible) buffering strategies and multiple locales.
|
||||||
|
It can be used for conventional I/O, reading and writing to memory (string streams),
|
||||||
|
and user-defines extensions, such as streaming across networks (asio: not yet standardized).
|
||||||
|
|
||||||
Iostream rule summary:
|
Iostream rule summary:
|
||||||
|
|
||||||
|
@ -17756,26 +17755,66 @@ Iostream rule summary:
|
||||||
##### Reason
|
##### Reason
|
||||||
|
|
||||||
Unless you genuinely just deal with individual characters, using character-level input leads to the user code performing potentially error-prone
|
Unless you genuinely just deal with individual characters, using character-level input leads to the user code performing potentially error-prone
|
||||||
and potentially inefficient composition of tokens out of characters.
|
and potentially inefficient composition ot tokens out of characters.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
??? compose a number ???
|
char c;
|
||||||
|
char buf[128];
|
||||||
|
int i = 0;
|
||||||
|
while (cin.get(c) && !isspace(c) && i < 128)
|
||||||
|
buf[i++] = c;
|
||||||
|
if (i == 128) {
|
||||||
|
// ... handle too long string ....
|
||||||
|
}
|
||||||
|
|
||||||
|
Better (much simpler and probably faster):
|
||||||
|
|
||||||
|
string s;
|
||||||
|
s.reserve(128);
|
||||||
|
cin>>s;
|
||||||
|
|
||||||
|
and the `reserve(128)` is probably not worthwhile.
|
||||||
|
|
||||||
|
##### Enforcement
|
||||||
|
|
||||||
|
???
|
||||||
|
|
||||||
|
|
||||||
### <a name="Rio-validate"></a>SL.io.2: When reading, always consider ill-formed input
|
### <a name="Rio-validate"></a>SL.io.2: When reading, always consider ill-formed input
|
||||||
|
|
||||||
|
##### Reason
|
||||||
|
|
||||||
|
Errors are typically best handled as soon as possible.
|
||||||
|
If input isn't validated, all every function must be writtent to cope with bad data (and that is not practical).
|
||||||
|
|
||||||
|
###### Example
|
||||||
|
|
||||||
|
???
|
||||||
|
|
||||||
|
##### Enforcement
|
||||||
|
|
||||||
???
|
???
|
||||||
|
|
||||||
### <a name="Rio-streams"></a>SL.io.3: Prefer `iostream`s for I/O
|
### <a name="Rio-streams"></a>SL.io.3: Prefer `iostream`s for I/O
|
||||||
|
|
||||||
##### Reason
|
##### Reason
|
||||||
|
|
||||||
`iostream`s are safe, flexible, and extensible.
|
`iosteam`s are safe, flexible, and extensible.
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
??? complex I/O ???
|
// write a complex number:
|
||||||
|
complex<double> z{ 3,4 };
|
||||||
|
cout << z << '\n';
|
||||||
|
|
||||||
|
`complex` is a user defined type and its I/O is defined without modifying the `iostream` library.
|
||||||
|
|
||||||
|
##### Example
|
||||||
|
|
||||||
|
// read a file of complex numbers:
|
||||||
|
for (complex<double> z; cin>>z)
|
||||||
|
v.push_back(z);
|
||||||
|
|
||||||
##### Exception
|
##### Exception
|
||||||
|
|
||||||
|
@ -17790,7 +17829,12 @@ implicit memory management, and `locale` handling.
|
||||||
|
|
||||||
If you need I/O performance, you can almost always do better than `printf()`.
|
If you need I/O performance, you can almost always do better than `printf()`.
|
||||||
|
|
||||||
|
`gets()` `scanf()` using `s`, and `printf()` using `%s` are security hazards (vulnerable to buffer overflow and generally error-prone).
|
||||||
|
In C++11, they are replaced by `gets_s()`, `scanf_s()`, and `printf_s()` as safer alternatives, but they are still not type safe.
|
||||||
|
|
||||||
|
##### Enforcement
|
||||||
|
|
||||||
|
Optionally flag `<cstdio>` and `<stdio.h>`.
|
||||||
|
|
||||||
### <a name="Rio-sync"></a>SL.io.10: Unless you use `printf`-family functions call `ios_base::sync_with_stdio(false)`
|
### <a name="Rio-sync"></a>SL.io.10: Unless you use `printf`-family functions call `ios_base::sync_with_stdio(false)`
|
||||||
|
|
||||||
|
@ -17836,11 +17880,14 @@ the choice between `'\n'` and `endl` is almost completely aesthetic.
|
||||||
|
|
||||||
## <a name="SS-regex"></a>SL.regex: Regex
|
## <a name="SS-regex"></a>SL.regex: Regex
|
||||||
|
|
||||||
???
|
`<regex>` is the standard C++ regular experssion library.
|
||||||
|
It supports a variety of regular exprssion pattern conventions.
|
||||||
|
|
||||||
## <a name="SS-chrono"></a>SL.chrono: Time
|
## <a name="SS-chrono"></a>SL.chrono: Time
|
||||||
|
|
||||||
???
|
`<chrono>` (defined in namespace `std::chrono`) provides the notions of `time_point` and `duration` together with functions for
|
||||||
|
outputting time in various units.
|
||||||
|
It provides clocks for registering `time_points`.
|
||||||
|
|
||||||
## <a name="SS-clib"></a>SL.C: The C standard library
|
## <a name="SS-clib"></a>SL.C: The C standard library
|
||||||
|
|
||||||
|
@ -17860,7 +17907,7 @@ a `longjmp` ignores destructors, thus invalidating all resource-management strat
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
|
|
||||||
Flag all occurrences of `longjmp`and `setjmp`
|
Flag all occurences of `longjmp`and `setjmp`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -19484,9 +19531,9 @@ Use literal suffixes where clarification is needed
|
||||||
|
|
||||||
###### Note
|
###### Note
|
||||||
|
|
||||||
Literals should not be sprinkled all over the code as ["magic constants"](#Res-magic),
|
Literals should not be springled all over the code as ["magic constants'](#Res-magic),
|
||||||
but it is still a good idea to make them readable where they are defined.
|
but it is still a good idea to make them readable where they are defined.
|
||||||
It is easy to make a typo in a long string of integers.
|
It is easy to make a yypo in a long string of integers.
|
||||||
|
|
||||||
###### Enforcement
|
###### Enforcement
|
||||||
|
|
||||||
|
@ -20643,7 +20690,7 @@ Alternatively, we will decide that no change is needed and delete the entry.
|
||||||
\[Meyers15]: S. Meyers. Effective Modern C++ (O'Reilly, 2015).
|
\[Meyers15]: S. Meyers. Effective Modern C++ (O'Reilly, 2015).
|
||||||
* <a name="Murray93"></a>
|
* <a name="Murray93"></a>
|
||||||
\[Murray93]: R. Murray. C++ Strategies and Tactics (Addison-Wesley, 1993).
|
\[Murray93]: R. Murray. C++ Strategies and Tactics (Addison-Wesley, 1993).
|
||||||
* <a name="Stroustrup94"></a>
|
* <a name="Stroustrup94"></a>
|
||||||
\[Stroustrup94]: B. Stroustrup. The Design and Evolution of C++ (Addison-Wesley, 1994).
|
\[Stroustrup94]: B. Stroustrup. The Design and Evolution of C++ (Addison-Wesley, 1994).
|
||||||
* <a name="Stroustrup00"></a>
|
* <a name="Stroustrup00"></a>
|
||||||
\[Stroustrup00]: B. Stroustrup. The C++ Programming Language (Special 3rdEdition) (Addison-Wesley, 2000).
|
\[Stroustrup00]: B. Stroustrup. The C++ Programming Language (Special 3rdEdition) (Addison-Wesley, 2000).
|
||||||
|
|
Loading…
Reference in New Issue
Block a user