-
Notifications
You must be signed in to change notification settings - Fork 5.5k
C.45 Enforcement about _user-defined non-defaulted_ default constructors #2297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C.45 Enforcement about _user-defined non-defaulted_ default constructors #2297
Conversation
Clarified that the Enforcement of "C.45: Don't define a default constructor that only initializes data members..." is specifically about _user-defined non-defaulted_ default constructors.
|
Editors call: Thanks! We decided to reword it a bit further, and thanks for pointing out it needed to be more precise. |
| ##### Enforcement | ||
|
|
||
| (Simple) A default constructor should do more than just initialize data members with constants. | ||
| (Simple) A user-defined non-defaulted default constructor should do more than just initialize data members with constants. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hsutter Thank you for reviewing my pull request. I'm very interested to see your rewording of this enforcement! Maybe you could just use the informal term "hand-written", rather than my proposed "user-defined non-defaulted" default constructor...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The standard has a term for exactly this:
[A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration.]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @jwakely I like the term "user-provided". However I think it's important to still add the term "non-defaulted" as well, in this particular Enforcement. As in:
"A user-provided non-defaulted default constructor should do more than just initialize data members with constants."
Because as far as I can see, it is OK for a user-provided defaulted default constructor to just initialize data members with constants. (It may still be defaulted after its first declaration.) Right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that the distinction really matters here, and the sentence gets harder to read with more terminology you squeeze into it.
Arguably, a function that is defaulted outside the class (i.e. not on its first declaration) does do more than just init members: it provides a non-inline definition of the symbol, which might be needed to preserve the library's ABI, or break a circular dependency by defining it after some other class is complete.
So that would be OK. A user-provided default constructor should either perform some non-trivial logic that can't be done by simple default member initializers, or it should accomplish something else that can't be done by defaulting it on first declaration.
Anyway, Herb's commit removes the term entirely. I don't think the word "explicit" in that commit adds any value though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, the enforcement appears quite different now, after Herb's commit (f52da2b):
CppCoreGuidelines/CppCoreGuidelines.md
Line 5802 in f52da2b
| (Simple) Flag if a default constructor's explicit member initializer is a constant, and recommend that the constant should be written as a data member initializer instead. |
I thought the original intention of this specific enforcement was: avoiding that programmers manually write default-constructors that can be defaulted instead (while still having the same behavior). Originally, the enforcement would ignore default-constructors that do other things than just initializing data members, for example:
class MyClass
{
public:
MyClass()
: data{ 42 }
{
std::cout << "Doing more than just initializing data!";
}
private:
int data;
};(In this example, the original enforcement would only get triggered after removing the print statement.)
| string s {"default"}; | ||
| int i {1}; | ||
| public: | ||
| // use compiler-generated default constructor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be an improvement to explicitly default the default ctor in the "good" example? That's needed if there are any other ctors declared (e.g. a copy or move ctor), and is more explicit about the intention.
| // use compiler-generated default constructor | |
| X() = default; |
Clarified that the Enforcement of C.45: Don't define a default constructor that only initializes data members... is specifically about user-defined non-defaulted default constructors.