Constructor implicitly deleted

Viewed 1188

The related code is listed below, you could check it on https://godbolt.org/z/3GH8zD. I could solve the complier compile error indeed.But i am not completely clear about the reason lie behind it.I would be grateful to have some help with this question.

struct A
{
    int x;
    A(int x = 1): x(x) {} // user-defined default constructor
};

struct F : public A
{
    int& ref; // reference member
    const int c; // const member
    // F::F() is implicitly defined as deleted
};

int main()
{
  F f; // compile error
}

Compiler compliains:

Could not execute the program

Compiler returned: 1

Compiler stderr

<source>:10:15: error: declaration does not declare anything [-fpermissive]

   10 |         const int; // const member

      |               ^~~

<source>: In function 'int main()':

<source>:16:9: error: use of deleted function 'F::F()'

   16 |       F f; // compile error

      |         ^

<source>:7:12: note: 'F::F()' is implicitly deleted because the default definition would be ill-formed:

    7 |     struct F : public A

      |            ^

<source>:7:12: error: uninitialized reference member in 'struct F'

<source>:9:14: note: 'int& F::ref' should be initialized

    9 |         int& ref; // reference member

      |              ^~~

The right code may be:

struct F
{
    int& ref = x; // reference member
    const int c = 1; // const member
    // F::F() is implicitly defined as deleted
};
3 Answers

The class member int& ref needs to be bound to an int when an object of type F is created.

A compiler-generated default constructor would not know how to bind it, so the compiler merely deletes the default constructor.

In the second snippet you explicitly set the member. (You can do that from C++11).

Have a look at the Deleted implicitly-declared default constructor section in cppreference. It explains under which circumstances the default constructor is deleted:

  • T has a member of reference type without a default initializer. (since C++11)
  • T has a const member without user-defined default constructor or a default member initializer (since C++11).

That is, if you don't default initialize your const and reference member variables, the constructor will be deleted and it also explains why your second attempt "worked". In fact, it doesn't work until you make F inherit from A (I guess this was your intention). Otherwise, you can't assign A::x to F::ref.

Note: Even though F::ref=A::x is allowed, there is no point in doing that since F already has access to A::x due to inheritance.

To try to build on @Bathsheba answer.

Let's first understand what a reference is. A reference is essentially a pointer that can't be null this makes them very tricky to initialize.

Let's look at your second class:

struct F : public A
{
    int& ref; // reference member
    const int c; // const member
    // F::F() is implicitly defined as deleted
};

If instead of defining it as int& ref; we define it as int ref; the compiler will say, I have no idea what ref is supoosed to be, so I'll stick some random value into it and be done. And so the default constructor just does ref = /*some num*/;

Let's say it was a pointer instead, i.e int* ref; Once again, the default constructor needs to initialize it to a value, for pointers the most logical value for default initialization is nullptr and so we get int* ref = nullptr;

But what if it is a reference? i.e int& ref;. We can;t initialize the variable to a number, because it is not a number it's a reference "i.e a pointer" to a number. But references can't be null so we can;t use nullptr either. So there is no valid default value initialization for the reference. The only reasonable thing is then to delete the default constructor because there does not exist any default value we can use to initialize one of its members.

Related