Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialization of const reference member in initializer list

I was playing with some useless code to understand initialization of member references, and bumped into this:

struct A {};

struct B
{
    B() : a()
    {
    }

    const A& a;
};

The code above gives the following error when compiled with gcc 4.9.2:

In constructor 'B::B()':
error: value-initialization of reference type 'const A&'
  B() : a()

Which I understand.

But if I use uniform initialization in B's constructor's initializer list, like so:

struct A {};

struct B
{
    B() : a{}
    {
    }

    const A& a;
};

It compiles fine.

So the question is, why does the use of uniform initialization here change the compilation result?

I also tried this with Microsoft Visual C++ 2013. It does not compile either version of the code, with the same error message:

Error 3 error C2440: 'initializing' : cannot convert from 'int' to 'const A & 

You can have a quick play with it here:

http://ideone.com/7f2t8I

like image 423
Hugo Avatar asked Feb 25 '15 11:02

Hugo


People also ask

How do you initialize const and reference member variables?

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.

How a const data member can be initialized?

The constant data member is initialized using the const keyword before the data type inside the class. The const data members cannot be assigned the values during its declaration; however, they can assign the constructor values. cout << " The value of constant data member 'A' is: " << obj.

How do you initialize a reference variable?

There are three steps to initializing a reference variable from scratch: declaring the reference variable; using the new operator to build an object and create a reference to the object; and. storing the reference in the variable.


1 Answers

GCC is correct in its interpretation of {}. [dcl.init.list]/p3.8-9 (quoting N4296; earlier drafts has the same relative ordering of these two bullets):

List-initialization of an object or reference of type T is defined as follows:

  • [7 inapplicable bullets omitted]

  • Otherwise, if T is a reference type, a prvalue temporary of the type referenced by T is copy-list-initialized or direct-list-initialized, depending on the kind of initialization for the reference, and the reference is bound to that temporary. [ Note: As usual, the binding will fail and the program is ill-formed if the reference type is an lvalue reference to a non-const type. —end note ]

  • Otherwise, if the initializer list has no elements, the object is value-initialized.

List-initializing the reference hits bullet 3.8, causing the construction of a temporary. The value-initialization case, in 3.9, doesn't apply.

Value-initialization of a reference is ill-formed ([dcl.init]/p9):

A program that calls for default-initialization or value-initialization of an entity of reference type is ill-formed.


However, as of N4296, per [class.base.init]/p8:

A temporary expression bound to a reference member in a mem-initializer is ill-formed.

This was added as a result of CWG issue 1696, which is a DR (defect report) against C++14.

Pre-CWG1696, the standard provided that (N4140 [class.temporary]/p5.1):

A temporary bound to a reference member in a constructor’s ctor-initializer (12.6.2) persists until the constructor exits.

which means that the reference will become dangling immediately after construction. This presumably motivated CWG1696's decision to disallow such bindings altogether.

like image 59
T.C. Avatar answered Oct 05 '22 15:10

T.C.