Home > Back-end >  Default member variables in defaulted copy/move constructors
Default member variables in defaulted copy/move constructors

Time:08-04

What exactly occurs to a member variable with a default value, during a defaulted copy/move construction? As so:

struct A {bool a = true;};

A x;
x.a = false;
A y = x;

I can imagine a few different ways this works, equivalently written as

struct A {bool a;}; //no default

//option 1
A::A(const A& other) noexcept : a(other.a) {}

//option 2
A::A(const A& other) noexcept : a(true) {a = other.a;}

//option 3
A::A(const A& other) noexcept {a = other.a;}

//option 4 (hopefully not)
A::A(const A& other) noexcept : a(true) {}

With the obvious exception that using these would make A not TriviallyCopyable

CodePudding user response:

A constructor must and will always initialize all the class data members.

Default initializers will be used in constructors where that data member isn't explicitly initialized. The default copy constructors will initialize each data member with a copy of the corresponding data member from the copied object, so default initializers won't be used.

This leads to a case where default initializers will be used in a copy constructor if it's user provided and it lacks that member initializer (thanks to NathanOliver for pointing this out).

E.g.:

A(whatever param) {}            // default initializer used
A(whatever param) : a{true} {}  // default initializer NOT used
A(const A&) = default;          // default initializer NOT used
A(const A&) : a{other.a} {}     // default initializer NOT used
A(const A&) {}                  // default initializer used

CodePudding user response:

Quick test, we'll see how the A's default Loud member is initialized and copied during A's defaulted copy constructor:

#include <iostream>
struct Loud {
    Loud(bool a) : b(a) {
        std::cout << "ctr with value " << b <<std::endl;
    }
    Loud(const Loud& other) noexcept : b(other.b) {
        std::cout << "cpyctr with value " << b << std::endl;
    }
    Loud& operator=(const Loud& other) noexcept {
        b = other.b;
        std::cout << "cpyasn with value " << b << std::endl;
        return *this;
    }
    bool b;
};
struct A {Loud a = true;};
int main(int argc, char** argv) {
    A x;         //1
    x.a = false; //2
    A y = x;     //3
    return 0;
}

On -O0, yielded:

ctr with value 1    //1 (constructing x)
ctr with value 0    //2 (implicit conversion from `false`)
cpyasn with value 0 //2 (assigning to x)
cpyctr with value 0 //3 (constructing y)

This implies the default constructor of A acted the same as

//option 1
A::A(const A& other) noexcept : a(other.a) {}

This supports the other answer (that the member having a default value) doesn't have any visible effect

  •  Tags:  
  • c
  • Related