Commit eebe6de4 authored by scott snyder's avatar scott snyder
Browse files

Some updates for c++17. Discourage protected data.

parent 80b80d85
......@@ -1664,6 +1664,23 @@ public:
Other possible exceptions include very tightly coupled classes and unit tests.
- *Avoid the use of protected data members.* [<<no-protected-data>>]
Protected data members are similar to friend declarations
in that they allow a controlled violation of encapsulation.
However, it is even less well-controlled in the case of protected
data, since any class may derive from the base class and access
the protected data.
The use of protected data results in one class depending on the
internals of another, which is a maintenance issue should the
base class need to change. Like friend declarations,
the use of protected member data should be avoided except
for very closely coupled classes (that should generally be part
of the same package). Rather, you should define a proper interface
for what needs to be done (parts of which may be protected).
** Notes on the use of library functions.
- *Use =std::abs= to calculate an absolute value.* [<<std-abs>>]
......@@ -2035,9 +2052,10 @@ public:
Experience has shown that exception specifications are generally not useful,
and they have been deprecated in C++11 [fn:sutter02]. They should not
be used in new code.
be used in new code. In C++17, the use of non-empty exception specifications
is an error.
C++ adds a new =noexcept= keyword. However, the motivation for this was
C++14 added a new =noexcept= keyword. However, the motivation for this was
really to address a specific problem with move constructors and
exception-safety, and it is not clear that it is
generally useful [fn:krzemienski14].
......@@ -2075,6 +2093,61 @@ public:
#+END_EXAMPLE
- *Prefer to catch exceptions as const reference, rather than as value.*
[<<catch-const-reference>>]
Classes used for exceptions can be polymorphic just like data classes,
and this is in fact the case for the standard C++ exceptions.
However, if you catch an exception and name the base class by value,
then the object thrown is copied to an instance of the base class.
For example, consider this program:
#+BEGIN_EXAMPLE -n
#include <stdexcept>
#include <iostream>
class myex : public std::exception {
public:
virtual const char* what() const noexcept
{ return "Mine!"; }
};
void foo()
{
throw myex();
}
int main()
{
try {
foo();
}
catch (std::exception ex) {
std::cout << "Exception: " << ex.what() << "\n";
}
return 0;
}
#+END_EXAMPLE
It looks like the intention here is to have a custom message printed
when the exception is caught. But that's not what happens --- this
program actually prints:
#+BEGIN_EXAMPLE -n
Exception: std::exception
#+END_EXAMPLE
That's because in the =catch= clause, the =myex= instance is copied
to a =std::exception= instance, so any information about the derived
=myex= class is lost. If we change the catch to use a reference instead:
#+BEGIN_EXAMPLE -n
catch (const std::exception ex&) {
#+END_EXAMPLE
then the program prints what was probably intended.
#+BEGIN_EXAMPLE -n
Exception: Mine!
#+END_EXAMPLE
** Parts of C++ to avoid
......@@ -2321,12 +2394,30 @@ some machines, left-to-right on others. -- end note ]
needed, and must not be used in ATLAS code.
- *Avoid pointer arithmetic.*
- *Avoid pointer arithmetic.* [<<no-pointer-arithmetic>>]
Pointer arithmetic reduces readability, and is extremely error prone.
It should be avoid outside of low-level code.
- *Do not declare variables with =register=.* [<<no-register>>]
The =register= keyword was originally intended as a hint to the compiler
that a variable will be used frequently, and therefore it would be good
to assign a dedicated register to that variable. However, compilers
have long been able to do a good job of assigning values to registers;
this is anyway highly-machine dependent.
The =register= keyword is ignored by all modern compilers, and has been
deprecated in the C++ standard for some time. As of C++17,
using the =register= keyword is an error.
If you absolutely need to assign a variable to a register, many compilers
have a way of doing this using inline assembly or a related facility.
This is, however, inherently compiler- and machine-dependent, and would
only be useful in very special cases.
** Readability and maintainability
- *Code should compile with no warnings.* [<<no-warnings>>]
......@@ -2874,6 +2965,13 @@ The comment includes the fact that it is the perpendicular distance.
* Changes
** Version 0.6
- The =register= keyword is an error in C++17.
- Dynamic exception specifications are errors in C++17.
- Exceptions should be caught using const references, by value.
- Discourage using protected data.
** Version 0.5
- Add an initial set of guidelines for AthenaMT.
- Add recommendation to prefer range-based for.
......@@ -3016,4 +3114,5 @@ Doxygen also knows about //!< , I think?
# LocalWords: AthReentrantAlgorithm ConcurrentFoo nonconst mutexes
# LocalWords: Impl impl getSize accessor TBB Karsten MyFlag myFlag
# LocalWords: declareProperty myFlagValue Diff'ing nconc defun 'org
# LocalWords: backend 'latex 'my 42ul 0pt 2ex Geant4
# LocalWords: backend 'latex 'my 42ul 0pt 2ex Geant4 myex 0pt 2ex
# LocalWords: 'org 'my
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment