This answer to What is The Rule of Three? has the following code. Notice that all constructors except the first one have = default;
at the end of them:
class person
{
std::string name;
int age;
public:
person(const std::string& name, int age); // Ctor
person(const person &) = default; // 1/5: Copy Ctor
person(person &&) noexcept = default; // 4/5: Move Ctor
person& operator=(const person &) = default; // 2/5: Copy Assignment
person& operator=(person &&) noexcept = default; // 5/5: Move Assignment
~person() noexcept = default; // 3/5: Dtor
};
Though I've seen it many times before, I don't understand when one might use = default
, or why. It seems to me if you want the default
constructor or assignment operator provided by C++, you can instead just remove that declaration (and any associated definition), no?
Is the purpose to explicitly forbid any other constructor of a given type? Ex: perhaps this
person& operator=(const person &) = default; // 2/5: Copy Assignment
sitting at the top of a class definition just makes it crystal clear to any reader or user of the class that no other manual/explicit copy assignment operator exists or can exist?
I could use some help with my understanding here:
- the mechanics / what all does it (ie: using
= default
after a constructor or function definition in a class) work on?- Would it work on the first constructor too? I don't see it on that one in the example:
person(const std::string& name, int age);
(also: does this constructor have a name? "general constructor" maybe?
- Would it work on the first constructor too? I don't see it on that one in the example:
- when to use
- why to use it
I'm still fairly new to the more advanced features of C++.
Update
Here is some additional insight from Scott Meyers: "A Concern about the Rule of Zero" (emphasis added):
(I'd probably make this an answer if this question wasn't closed).
The addition of the destructor has the side effect of disabling generation of the move functions, but because Widget is copyable, all the code that used to generate moves will now generate copies. In other words, adding a destructor to the class has caused presumably-efficient moves to be silently replaced with presumably-less-efficient copies. That strikes me as the kind of thing that (1) is likely to surprise people and (2) could really complicate debugging.
I'm inclined to recommend that a better way to rely on the compiler-generated copy and move functions is to expressly say that they do the right thing--to define them via
=default
:class Widget { public: Widget(const Widget&) = default; Widget(Widget&&) = default; Widget& operator=(const Widget&) = default; Widget& operator=(Widget&&) = default; ... };
With this approach, the spirit of the Rule of Zero remains: classes that don't manage resources should be designed so that the compiler-generated functions for copying, moving, and destruction do the right things. But instead of expressing this by not declaring those functions, it's expressed by declaring them explicitly and equally explicitly opting in to the compiler-generated implementations.
What do you think? Does this advice make sense? Should the Rule of Zero perhaps be the Rule of the Five defaults?
That is the end of Scott's blog post. Then, in the comments beneath his post, he states:
I think "The Rule of All or Nothing" would be a pretty good rule.
Response to being marked as a duplicate / request to re-open this question:
I feel like the question marked as "already has an answer" here doesn't cover the nuances of the question I'm asking, and my question should be reopened to allow others to contribute more answers and insight regarding the specifics of my question. I've looked at its answers. It's question focuses on explicitly default
ing a generic constructor, but my question focuses on explicitly default
ing one or more of the "Rule of 5" constructors/assignment operators, and how that affects the interactions and responses of the others. I'm voting to re-open my question now.
Sandbox: https://godbolt.org/z/vWMsd3