C++ Logo

std-proposals

Advanced search

Re: Variables in constructor member initializer list

From: Artyom Lebedev <artyom.lebedev_at_[hidden]>
Date: Wed, 1 Sep 2021 12:23:16 +0300
On 9/1/21 11:58 AM, Bo Persson via Std-Proposals wrote:
> On 2021-09-01 at 10:44, Artyom Lebedev via Std-Proposals wrote:
>> Hello,
>>
>> Consider the following code:
>>
>> class MyClass {
>> public:
>> const int a, b, c;
>>
>> MyClass(SomeObject &someObject):
>> a(SomeOperation(someObject.GetSomeValue()) * 2),
>> b(SomeOperation(someObject.GetSomeValue()) / 3),
>> c(SomeOperation(someObject.GetSomeValue()) + 4)
>> {}
>> };
>>
>> In such a typical case it is very inconvenient to have no possibility
>> to store value of repeating expression. Also it might be very
>> suboptimal to repeatedly call some potentially heavy functions to
>> have the same result. I propose to introduce variables in the members
>> initializer list:
>>
>> class MyClass {
>> public:
>> const int a, b, c;
>>
>> MyClass(SomeObject &someObject):
>> int someBaseValue(SomeOperation(someObject.GetSomeValue())),
>> a(someBaseValue * 2),
>> b(someBaseValue / 3),
>> c(someBaseValue + 4)
>> {}
>> };
>>
>> Possible workarounds:
>>
>> 1. Introduce class member to store temporal value:
>>
>> class MyClass {
>> public:
>> const int someBaseValue, a, b, c;
>>
>> MyClass(SomeObject &someObject):
>> someBaseValue(SomeOperation(someObject.GetSomeValue())),
>> a(someBaseValue * 2),
>> b(someBaseValue / 3),
>> c(someBaseValue + 4)
>> {}
>> };
>>
>> which is waste of space, since that value is not needed after useful
>> members are initialized.
>>
>> 2. Use static method to shorten repeated expression:
>>
>> class MyClass {
>> public:
>> const int a, b, c;
>>
>> MyClass(SomeObject &someObject):
>> a(GetSomeBaseValue() * 2),
>> b(GetSomeBaseValue() / 3),
>> c(GetSomeBaseValue() + 4)
>> {}
>>
>> static inline int
>> GetSomeBaseValue(SomeObject &someObject)
>> {
>> return SomeOperation(someObject.GetSomeValue());
>> }
>> };
>>
>> but there still are repeated calls to potentially heavy operation.
>>
>> 3. Use assignment instead of initialization:
>>
>> class MyClass {
>> public:
>> int a, b, c;
>>
>> MyClass(SomeObject &someObject)
>> {
>> int someBaseValue = SomeOperation(someObject.GetSomeValue());
>> a = GetSomeBaseValue() * 2);
>> b = GetSomeBaseValue() / 3);
>> c = GetSomeBaseValue() + 4);
>> }
>> };
>>
>> but it is 1. suboptimal due to wasted members intialization which may
>> be heavy for some classes, 2. Impossible to use for immutable classes
>> which do not support assignment, 3. impossible to use for const members.
>>
>
> You can alredy get a similar effect by using a delegating constructor:
>
> class MyClass {
> public:
> const int a, b, c;
>
> MyClass(SomeObject &someObject)
> : MyClass(SomeOperation(someObject.GetSomeValue()))
> {}
>
> private:
> MyClass(int someBaseValue) :
> a(someBaseValue * 2),
> b(someBaseValue / 3),
> c(someBaseValue + 4)
> {}
> };
>
You are right, I missed this feature. However, it is still a matter of
convenience. Besides passing list of parameters, you also need to ensure
the delegating constructor signature is not colliding with any other
constructor, requiring constructions like this:

class MyClass {
public:
     const int a, b, c;

     MyClass(int someBaseValue)
      : MyClass(SomeHeavyOperation(someBaseValue), ConstructorTag())
     {}

private:
     struct ConstructorTag {};

     MyClass(int someDerivedValue, ConstructorTag) :
         a(someDerivedValue * 2),
         b(someDerivedValue / 3),
         c(someDerivedValue + 4)
     {}
};

or introducing dedicated structure for passing construction parameters
in, which is quite verbose.

Introducing delegated constructors made much code less verbose.
Introducing variables in member initializer list could make the next
step to make it even neater.

-- 
Best regards,
Artyom.

Received on 2021-09-01 04:23:23