why default constructor is not used in value initialisation in c++

78 views Asked by At

c++ primer says :

The default constructor is used automatically whenever an object is default or value initialized.
Default initialization happens
• When we define nonstatic variables (§ 2.2.1, p. 43) or arrays (§ 3.5.1, p. 114) at block scope without initializers
• When a class that itself has members of class type uses the synthesized de- fault constructor (§ 7.1.4, p. 262)
• When members of class type are not explicitly initialized in a constructor initializer list (§ 7.1.4, p. 265)
Value initialization happens
• During array initialization when we provide fewer initializers than the size of the array (§ 3.5.1, p. 114)
• When we define a local static object without an initializer (§ 6.1.1, p. 205) • When we explicitly request value initialization by writing an expressions of the form T() where T is the name of a type (The vector constructor that takes a single argument to specify the vector’s size (§ 3.3.1, p. 98) uses an argument of this kind to value initialize its element initializer.)
Classes must have a default constructor in order to be used in these contexts. Most of these contexts should be fairly obvious

class foo{
public :
    int data;
    foo() = default;
};

int main(){
    std::vector<foo> fvec1;
    std::vector<foo> fvec2(4,foo(2));
    foo f[5]{1,2,4};
    std::cout << fvec2[1].data << " " << f[4].data << std::endl;
}

Output :

error: no matching function for call to ‘foo::foo(int)’
    std::vector<foo> fvec2(4, foo(2));
                              ^
error: could not convert ‘1’ from ‘int’ to ‘foo’
       foo f[5]{1,2,4};
                ^

But if we remove the following line

foo() = default;

the code works, while synthesised default constructor is used, why not a default constructor declared as default, why I am not getting the default behaviour though declared default.
And if possible can any one provide examples for above reasons said by 'c++ primer', because it is so confusing.

standard : c++ 20
compiler : g++-12, clang++-15

1

There are 1 answers

2
NathanOliver On BEST ANSWER

So we have a couple of things going on here. First is that foo in the form of

class foo{
public :
    int data;
};

is an aggregate. An aggregate can be initialized with {} and beginning in C++20 that was expanded to include () for initialization as well. That means in

std::vector<foo> fvec2(4,foo(2));
//and
foo f[5]{1,2,4}

that you aggregate initialize the objects.

When you change foo to

class foo{
public :
    int data;
    foo() = default;
};

You no longer have an aggregate because you have a user declared constructor. This means that to value initialize it you need to provide a constructor that takes in the value(s) that are needed to construct the class. You do that by adding a constructor like

class foo{
public :
    int data;
    foo() = default;
    foo(int data_) : data(data_) {}
};