Hugo
Hugo

Reputation: 145

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

Upvotes: 9

Views: 3865

Answers (1)

T.C.
T.C.

Reputation: 137310

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.

Upvotes: 7

Related Questions