Doc. No.: | N4401 |
---|---|
Date: | 2015-04-07 |
Project: | Programming Language C++, Evolution Working Group |
Reply To: | Michael Price <michael.b.price.dev@gmail.com> |
Argues that WG21 should keep the semantics of any compiler-generated
comparison operators uniform with those of other compiler-generated
special member functions; specifically that mutable
and pointer members should be included in the default comparison
operations.
Given the following types and their relationships
struct Base {
std::string name;
};
class Member {
int value;
};
class MyType : public Base {
mutable Member member;
std::string * id;
};
We have existing rules that determine what happens during the constructor
of an instance of MyType
.
Paragraph 12.6.2.13 [1] reads:
In a non-delegating constructor, initialization proceeds in the following order:
—First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where "left-to-right" is the order of appearance of the base classes in the derived class base-specifier-list,
—Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
—Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
—Finally, the compound-statement of the constructor body is executed.
[Note: The declaration order is mandated to ensure that the base and member subobjects are destroyed in the reverse order of initialization. —end note]
The ordering rules for implictly defined copy and move constructors (12.8.15) reference paragraph 12.6.2, and the ordering for implicity defined copy and move assignment operators (12.8.28) are similarly described.
Paragraph 12.8.15 [1] reads:
The implicitly-defined copy/move constructor for a non-union class
X
performs a memberwise copy/move of its bases and members. [Note: brace-or-equal-initializers of non-static dta members are ignored. See also the example in 12.6.2. —end note] The order of initialization is the same as the order of initialization of bases and members in a user-defined constructor (see 12.6.2). Letx
be either the parameter of the constructor or, for the move constructor, an xvalue referring to the parameter. Each base or non-static data member is copied/moved in the manner appropriate to its type:
—if the member is an array, each element is direct-initialized with the corresponding subobject ofx
;
—if a memberm
has rvalue reference typeT&&
, it is direct-initialized withstatic_cast<T&&>(x.m)
;
—otherwise, the base or member is direct-initialized with the corresponding base or memberx
.
Virtual base class subobjects shall be initialized only once by the implicitly-defined copymove constructor (see 12.6.2).
Paragraph 12.8.28 [1] reads:
The implicitly-defined copy/move assignment operator for a non-union class
X
performs memberwise copy/move assignment of its subobjects. The direct base classes ofX
are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate non-static data members ofX
are assigned, in the order in which they were declared in the class definition. Letx
be either the parameter of the function or, for the move operator, an xvalue referring to the parameter. Each subobject is asigne din the manner appropriate to its type:
—if the subobject is of class type, as if by a call tooperator=
with the subobject as the object expression and the corresponding subobject ofx
as a single function argument (as if by explicity qualification; that is, ignoring any possible virtual overriding functions in more derived classes);
—if the subobject is an array, each element is assigned, in the manner appropriate to the element type;
—if the subobject is of scalar type, the built-in assignment operator is used.
It is unspecified whether subobjects representing virtual base classes are assigned more than once by the implicitly-defined copy/move assignment operator.
Tellingly, we have no special considerations for members that could possibly
cause undesired behavior, particularly for mutable
and pointer
members. We've left it to the designer of MyType
to understand
whether the generated special member functions satisfy the requirements for
the type, and if they do not, they are free to implement the desired semantics.
In N4175 [2], it was argued that mutable
and pointer members should be excluded from default-generated comparison
operators. The general argument is that any generated comparison operators
for those kinds of members might not be what a user expects; ordered
comparisons for pointers currently have serious problems and comparing a
mutable
member could have side-effects on its value. Those
concerns are valid, but that is our current state with regards to other
generated special member functions. Therefore, the proposal to include
those types in the default comparisons are likely to only be palatable if
we agree to restrict the generation to those cases where we believe it
should be a safe operation, or to impose stricter requirements, such as
forcing the author to explicitly opt-in to the default behavior by
requiring the author of a type to request the default implementation via
= default;
.
Complicating the special member functions by ignoring components of an instance's value for a subset of those functions doesn't seem like the best path forward to this author. Instead, we should not try to assume too much about the intention of the author of a class and trust that they understand that the use of "unusual" types as members requires doing extra work, as we have maintained for the past several decades.
Many thanks to my employer, Lexmark International, for continuing to support my work on the committee. Several of my co-workers, Andrew Regier, Chris Sammis, and Serhan Yengulalp, provided invaluable feedback on early drafts that led me to clarify my position and address previously ignored issues.