#1191 replace member variable with data member (#2087)

Co-authored-by: Herb Sutter <herb.sutter@gmail.com>
This commit is contained in:
Jan Schultke 2024-01-18 22:20:40 +01:00 committed by GitHub
parent 85e2fa321f
commit 41426a1a5f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -4820,7 +4820,7 @@ Constructor rules:
* [C.44: Prefer default constructors to be simple and non-throwing](#Rc-default00) * [C.44: Prefer default constructors to be simple and non-throwing](#Rc-default00)
* [C.45: Don't define a default constructor that only initializes data members; use member initializers instead](#Rc-default) * [C.45: Don't define a default constructor that only initializes data members; use member initializers instead](#Rc-default)
* [C.46: By default, declare single-argument constructors `explicit`](#Rc-explicit) * [C.46: By default, declare single-argument constructors `explicit`](#Rc-explicit)
* [C.47: Define and initialize member variables in the order of member declaration](#Rc-order) * [C.47: Define and initialize data members in the order of member declaration](#Rc-order)
* [C.48: Prefer default member initializers to member initializers in constructors for constant initializers](#Rc-in-class-initializer) * [C.48: Prefer default member initializers to member initializers in constructors for constant initializers](#Rc-in-class-initializer)
* [C.49: Prefer initialization to assignment in constructors](#Rc-initialize) * [C.49: Prefer initialization to assignment in constructors](#Rc-initialize)
* [C.50: Use a factory function if you need "virtual behavior" during initialization](#Rc-factory) * [C.50: Use a factory function if you need "virtual behavior" during initialization](#Rc-factory)
@ -5018,10 +5018,10 @@ These operations disagree about copy semantics. This will lead to confusion and
##### Enforcement ##### Enforcement
* (Complex) A copy/move constructor and the corresponding copy/move assignment operator should write to the same member variables at the same level of dereference. * (Complex) A copy/move constructor and the corresponding copy/move assignment operator should write to the same data members at the same level of dereference.
* (Complex) Any member variables written in a copy/move constructor should also be initialized by all other constructors. * (Complex) Any data members written in a copy/move constructor should also be initialized by all other constructors.
* (Complex) If a copy/move constructor performs a deep copy of a member variable, then the destructor should modify the member variable. * (Complex) If a copy/move constructor performs a deep copy of a data member, then the destructor should modify the data member.
* (Complex) If a destructor is modifying a member variable, that member variable should be written in any copy/move constructors or assignment operators. * (Complex) If a destructor is modifying a data member, that data member should be written in any copy/move constructors or assignment operators.
## <a name="SS-dtor"></a>C.dtor: Destructors ## <a name="SS-dtor"></a>C.dtor: Destructors
@ -5144,9 +5144,9 @@ Here `p` refers to `pp` but does not own it.
##### Enforcement ##### Enforcement
* (Simple) If a class has pointer or reference member variables that are owners * (Simple) If a class has pointer or reference members that are owners
(e.g., deemed owners by using `gsl::owner`), then they should be referenced in its destructor. (e.g., deemed owners by using `gsl::owner`), then they should be referenced in its destructor.
* (Hard) Determine if pointer or reference member variables are owners when there is no explicit statement of ownership * (Hard) Determine if pointer or reference members are owners when there is no explicit statement of ownership
(e.g., look into the constructors). (e.g., look into the constructors).
### <a name="Rc-dtor-ptr"></a>C.32: If a class has a raw pointer (`T*`) or reference (`T&`), consider whether it might be owning ### <a name="Rc-dtor-ptr"></a>C.32: If a class has a raw pointer (`T*`) or reference (`T&`), consider whether it might be owning
@ -5491,7 +5491,7 @@ If a valid object cannot conveniently be constructed by a constructor, [use a fa
##### Enforcement ##### Enforcement
* (Simple) Every constructor should initialize every member variable (either explicitly, via a delegating ctor call or via default construction). * (Simple) Every constructor should initialize every data member (either explicitly, via a delegating ctor call or via default construction).
* (Unknown) If a constructor has an `Ensures` contract, try to see if it holds as a postcondition. * (Unknown) If a constructor has an `Ensures` contract, try to see if it holds as a postcondition.
##### Note ##### Note
@ -5784,7 +5784,7 @@ Using default member initializers lets the compiler generate the function for yo
##### Enforcement ##### Enforcement
(Simple) A default constructor should do more than just initialize member variables with constants. (Simple) A default constructor should do more than just initialize data members with constants.
### <a name="Rc-explicit"></a>C.46: By default, declare single-argument constructors explicit ### <a name="Rc-explicit"></a>C.46: By default, declare single-argument constructors explicit
@ -5824,7 +5824,7 @@ Copy and move constructors should not be made `explicit` because they do not per
(Simple) Single-argument constructors should be declared `explicit`. Good single argument non-`explicit` constructors are rare in most code bases. Warn for all that are not on a "positive list". (Simple) Single-argument constructors should be declared `explicit`. Good single argument non-`explicit` constructors are rare in most code bases. Warn for all that are not on a "positive list".
### <a name="Rc-order"></a>C.47: Define and initialize member variables in the order of member declaration ### <a name="Rc-order"></a>C.47: Define and initialize data members in the order of member declaration
##### Reason ##### Reason
@ -5894,7 +5894,7 @@ How would a maintainer know whether `j` was deliberately uninitialized (probably
##### Enforcement ##### Enforcement
* (Simple) Every constructor should initialize every member variable (either explicitly, via a delegating ctor call or via default construction). * (Simple) Every constructor should initialize every data member (either explicitly, via a delegating ctor call or via default construction).
* (Simple) Default arguments to constructors suggest a default member initializer might be more appropriate. * (Simple) Default arguments to constructors suggest a default member initializer might be more appropriate.
### <a name="Rc-initialize"></a>C.49: Prefer initialization to assignment in constructors ### <a name="Rc-initialize"></a>C.49: Prefer initialization to assignment in constructors
@ -7719,7 +7719,7 @@ Consider making such a class a `struct` -- that is, a behaviorless bunch of vari
int y {0}; int y {0};
}; };
Note that we can put default initializers on member variables: [C.49: Prefer initialization to assignment in constructors](#Rc-initialize). Note that we can put default initializers on data members: [C.49: Prefer initialization to assignment in constructors](#Rc-initialize).
##### Note ##### Note
@ -10918,7 +10918,7 @@ Many such errors are introduced during maintenance years after the initial imple
##### Example ##### Example
This rule covers member variables. This rule covers data members.
class X { class X {
public: public:
@ -14554,7 +14554,7 @@ but we can mention:
and some older versions of [GCC](https://gcc.gnu.org/wiki/ThreadSafetyAnnotation) and some older versions of [GCC](https://gcc.gnu.org/wiki/ThreadSafetyAnnotation)
have some support for static annotation of thread safety properties. have some support for static annotation of thread safety properties.
Consistent use of this technique turns many classes of thread-safety errors into compile-time errors. Consistent use of this technique turns many classes of thread-safety errors into compile-time errors.
The annotations are generally local (marking a particular member variable as guarded by a particular mutex), The annotations are generally local (marking a particular data member as guarded by a particular mutex),
and are usually easy to learn. However, as with many static tools, it can often present false negatives; and are usually easy to learn. However, as with many static tools, it can often present false negatives;
cases that should have been caught but were allowed. cases that should have been caught but were allowed.
@ -15784,7 +15784,7 @@ Sometimes C++ code allocates the `volatile` memory and shares it with "elsewhere
##### Example, bad ##### Example, bad
`volatile` local variables are nearly always wrong -- how can they be shared with other languages or hardware if they're ephemeral? `volatile` local variables are nearly always wrong -- how can they be shared with other languages or hardware if they're ephemeral?
The same applies almost as strongly to member variables, for the same reason. The same applies almost as strongly to data members, for the same reason.
void f() void f()
{ {
@ -15793,7 +15793,7 @@ The same applies almost as strongly to member variables, for the same reason.
} }
class My_type { class My_type {
volatile int i = 0; // suspicious, volatile member variable volatile int i = 0; // suspicious, volatile data member
// etc. // etc.
}; };
@ -15803,7 +15803,7 @@ In C++, unlike in some other languages, `volatile` has [nothing to do with synch
##### Enforcement ##### Enforcement
* Flag `volatile T` local and member variables; almost certainly you intended to use `atomic<T>` instead. * Flag `volatile T` local and data members; almost certainly you intended to use `atomic<T>` instead.
* ??? * ???
### <a name="Rconc-signal"></a>CP.201: ??? Signals ### <a name="Rconc-signal"></a>CP.201: ??? Signals
@ -16959,7 +16959,7 @@ it offers to its users.
##### Enforcement ##### Enforcement
* Flag a member function that is not marked `const`, but that does not perform a non-`const` operation on any member variable. * Flag a member function that is not marked `const`, but that does not perform a non-`const` operation on any data member.
### <a name="Rconst-ref"></a>Con.3: By default, pass pointers and references to `const`s ### <a name="Rconst-ref"></a>Con.3: By default, pass pointers and references to `const`s
@ -21181,7 +21181,7 @@ Type safety profile summary:
Prefer [construction](#Res-construct) or [named casts](#Res-casts-named) or `T{expression}`. Prefer [construction](#Res-construct) or [named casts](#Res-casts-named) or `T{expression}`.
* <a name="Pro-type-init"></a>Type.5: Don't use a variable before it has been initialized: * <a name="Pro-type-init"></a>Type.5: Don't use a variable before it has been initialized:
[always initialize](#Res-always). [always initialize](#Res-always).
* <a name="Pro-type-memberinit"></a>Type.6: Always initialize a member variable: * <a name="Pro-type-memberinit"></a>Type.6: Always initialize a data member:
[always initialize](#Res-always), [always initialize](#Res-always),
possibly using [default constructors](#Rc-default0) or possibly using [default constructors](#Rc-default0) or
[default member initializers](#Rc-in-class-initializer). [default member initializers](#Rc-in-class-initializer).
@ -22244,9 +22244,9 @@ Modernization can be much faster, simpler, and safer when supported with analysi
This section contains follow-up material on rules and sets of rules. This section contains follow-up material on rules and sets of rules.
In particular, here we present further rationale, longer examples, and discussions of alternatives. In particular, here we present further rationale, longer examples, and discussions of alternatives.
### <a name="Sd-order"></a>Discussion: Define and initialize member variables in the order of member declaration ### <a name="Sd-order"></a>Discussion: Define and initialize data members in the order of member declaration
Member variables are always initialized in the order they are declared in the class definition, so write them in that order in the constructor initialization list. Writing them in a different order just makes the code confusing because it won't run in the order you see, and that can make it hard to see order-dependent bugs. Data members are always initialized in the order they are declared in the class definition, so write them in that order in the constructor initialization list. Writing them in a different order just makes the code confusing because it won't run in the order you see, and that can make it hard to see order-dependent bugs.
class Employee { class Employee {
string email, first, last; string email, first, last;
@ -22264,7 +22264,7 @@ Member variables are always initialized in the order they are declared in the cl
In this example, `email` will be constructed before `first` and `last` because it is declared first. That means its constructor will attempt to use `first` and `last` too soon -- not just before they are set to the desired values, but before they are constructed at all. In this example, `email` will be constructed before `first` and `last` because it is declared first. That means its constructor will attempt to use `first` and `last` too soon -- not just before they are set to the desired values, but before they are constructed at all.
If the class definition and the constructor body are in separate files, the long-distance influence that the order of member variable declarations has over the constructor's correctness will be even harder to spot. If the class definition and the constructor body are in separate files, the long-distance influence that the order of data member declarations has over the constructor's correctness will be even harder to spot.
**References**: **References**:
@ -22988,7 +22988,7 @@ Alternatively, we will decide that no change is needed and delete the entry.
* Should there be inline namespaces (à la `std::literals::*_literals`)? * Should there be inline namespaces (à la `std::literals::*_literals`)?
* Avoid implicit conversions * Avoid implicit conversions
* Const member functions should be thread safe ... aka, but I don't really change the variable, just assign it a value the first time it's called ... argh * Const member functions should be thread safe ... aka, but I don't really change the variable, just assign it a value the first time it's called ... argh
* Always initialize variables, use initialization lists for member variables. * Always initialize variables, use initialization lists for data members.
* Anyone writing a public interface which takes or returns `void*` should have their toes set on fire. That one has been a personal favorite of mine for a number of years. :) * Anyone writing a public interface which takes or returns `void*` should have their toes set on fire. That one has been a personal favorite of mine for a number of years. :)
* Use `const`-ness wherever possible: member functions, variables and (yippee) `const_iterators` * Use `const`-ness wherever possible: member functions, variables and (yippee) `const_iterators`
* Use `auto` * Use `auto`