Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delegating copy constructor and const data initialization

I have a class A with lots of data members, some of which are constant. All data members have proper copy constructors, so I want to default a copy constructor of my class:

class A
{
public:
        A() : a(1) {}
        A(const A& op) = default;
private:
        // ... Lots of constant and non-constant member data ...
        const int a;
};

Then, I want to write a constructor which accepts a reference to A and a value which should initialize one of constant data members:

A(const A& op, const int a_);

Here op should be copied, and a should be initialized with a_ after that or instead of copying. I would like to avoid manual initialization of all data members by delegating to a copy constructor, but how to overwrite my const data member in this case? For example:

// Illegal: constructor delegation can't be mixed with field initialization.
A(const A& op, const int a_) : A(op), a(a_) {}

// Illegal: attempt to assign constant member.
A(const A& op, const int a_) : A(op) { a = a_; } 

// Hack. May lead to UB in some cases.
A(const A& op, const int a_) : A(op)
{
    *(const_cast<int*>(&a)) = a_;
    // ... or same tricks with memcpy ...
}

Obviously, all of these approaches are evil as they try to initialize a twice.

Another solution is to move all constant data to a base class and write all needed ctors, but it looks to verbose.

Is there a cleaner way to implement A(const A&, int a_)?

like image 788
Sergey Avatar asked Aug 01 '17 08:08

Sergey


People also ask

What is a delegating constructor?

Delegating constructors. Constructors are allowed to call other constructors from the same class. This process is called delegating constructors (or constructor chaining). To have one constructor call another, simply call the constructor in the member initializer list.

Can const be initialized in constructor?

A constructor can initialize an object that has been declared as const , volatile or const volatile .

How a const data member can be initialized?

To initialize the const value using constructor, we have to use the initialize list. This initializer list is used to initialize the data member of a class. The list of members, that will be initialized, will be present after the constructor after colon. members will be separated using comma.

Does const need to be initialized?

When a variable is declared as const it means that , variable is read-only ,and cant be changed . so in order to make a variable read only it should be initialized at the time it is declared.


1 Answers

Unfortunately, C++ const field initialization is a very special case with specific syntax, so is constructor delegation, and the constructor syntax has no provision to mix them, so there can be no clean and neat solution here (at least for current C++ versions, maybe later...). The best I can imagine is:

class A
{
public:
        A() : a(1) {}
        A(const A& op):
             const_field1(op.const_field1),..., a(op.a) // all const fields here
           { init() };
        A(const A& op, int a_):
             const_field1(op.const_field1),..., a(a))   // dup line at editor level

private:
        void init(void) {
            // init non const fields here
        }
        // ... Lots of constant and non-constant member data ...
        const int a;
};

It does not make sense if you have only the copy ctor and one single additional one, but it could ease code maintenability if you have many additional ctors. It is a pity that only non const field setting can be factorized across different ctors with a private method, but C++ standard is like that.

like image 151
Serge Ballesta Avatar answered Oct 15 '22 17:10

Serge Ballesta