Recently, I was unhappy to find that I often ended up reproducing the constructor's behavior every time I had to create a "reset" function for an object.
Example:
class Foo
{
int i;
public:
Foo() : i(42) {};
void reset() {
i = 42;
}
};
To solve this problem, I came up with the idea of calling the constructor directly in the reset function to ensure that the behavior is the same.
Modified example:
class Foo
{
int i;
public:
Foo() : i(42) {};
void reset() {
*this = {};
}
};
This worked well, but a couple of questions came to mind that I haven't found the answer to yet:
Thanks
Yes, it's fine.
What you are doing is using the implicitly defined operator= (given for free by the compiler since you did not define one yourself).
The operator= expects a reference to another Foo object:
operator=(const Foo&)
or
operator=(Foo&&)
You are giving it an empty list initializing which is perfectly defined for the Foo you created, as a class constructor that is not marked as explicit is a definition for a possible implicit conversion from the list of arguments given to a class constructed by the matching constructor.
In your case, since you are giving an empty list, you simply ask for implicit conversion to Foo{}, meaning that you wish for this code:
*this = Foo{};
which means to assign my object with the default constructed Foo, which is born with i=42.
The default operator= would simply bitwise-copy the object given as an argument into the executing object (*this).
So after this, you get that this->i = 42.
It is perfectly defined but without optimization, it is less efficient than your first version. However, it is a premature optimization you need to identify that it is not optimized before preferring a code that is more complex to understand.
Your first coding version has code duplication. In the second version, you communicate clearly to fellow programmers that this is a default Foo and you reset to one.
See how without optimization your first version is more efficient and requires fewer assembly instructions here. However, it is being optimized even with minimal optimization -O1 for instance. So I wouldn't be worried about it unless proven otherwise by a relevant benchmark.
If proven that code is inefficient, you can do this with minimal code duplication and a coding pattern that would be safer (less bug prone):
class Foo
{
int m1 = m1_reset();
int m2 = m2_reset();
constexpr void internal_reset() {
m1 = m1_reset();
m2 = m2_reset();
}
constexpr int m1_reset() { return 42; }
constexpr int m2_reset() { return 84; }
public:
constexpr Foo() = default;
void reset() {
internal_reset();
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With