2016-09-08 10 views
1

Вот моя ситуация:C++ 11 в классе инициализация ссылки член делает плохую копию

  • У меня есть класс, который имеет константный переменный базовый элемент.
  • Я пытаюсь инициализировать эту переменную-член из ссылки const.

Моя проблема заключается в том, что когда переменная-член инициализируется в классе, создается временная копия рассматриваемого объекта и адрес ссылки используется для ссылки. Когда переменная-член инициализируется в списке инициализаторов конструктора, копия не создается. В любом случае программа компилируется без предупреждений в g ++ 4.8.3 с флагами C++ 11 или C++ 1y.

Ниже представлена ​​минимальная программа и выход. Я просто хотел бы понять правила этого лучше, поэтому я знаю, почему это происходит (или если это ошибка).

#include <iostream> 
using namespace std; 
struct A 
{ 
    A() 
    { 
     cout << "creating an A at " << this << endl; 
    } 

    A(const A & a) 
    { 
     cout << "copying an A from instance at " << & a << " to instance at " << this << endl; 
    } 
}; 

A g_aardvark; 

const A & GetAardvark() 
{ 
    cout << "returning an A at " << & g_aardvark << endl; 
    return g_aardvark; 
} 

struct B 
{ 
    B() 
     : m_a1(GetAardvark()) 
     , m_a2(g_aardvark) 
    { } 
    const A & m_a1; 
    const A & m_a2; 
    const A & m_a3{ GetAardvark() }; 
    const A & m_a4{ g_aardvark }; 
}; 

int main() 
{ 
    B butter; 
    cout << "B has m_a1 at " << & butter.m_a1 << endl; 
    cout << "B has m_a2 at " << & butter.m_a2 << endl; 
    cout << "B has m_a3 at " << & butter.m_a3 << endl; 
    cout << "B has m_a4 at " << & butter.m_a4 << endl; 
    return 0; 
} 

Пример вывода:

creating an A at 0x601494 
returning an A at 0x601494 
returning an A at 0x601494 
copying an A from instance at 0x601494 to instance at 0x7fffc595f87f 
copying an A from instance at 0x601494 to instance at 0x7fffc595f87e 
B has m_a1 at 0x601494 
B has m_a2 at 0x601494 
B has m_a3 at 0x7fffc595f87f 
B has m_a4 at 0x7fffc595f87e 
+0

Если память служит, это было ошибкой в ​​списке-инициализации ссылок gcc, зафиксированном в 4.9. Вы должны иметь возможность воспроизводить гораздо более простой код, например. 'int main() {A a; A const & b {a}; } ' –

+0

Какую версию компилятора вы используете? В этом коде нет копий: http://coliru.stacked-crooked.com/a/f30df5ef62b45420 –

ответ

2

Это случай печально известной DR 1288. Был дефект в опубликованный стандарт C++ 11, которые непреднамеренно указано, что код:

const A & m_a4{ g_aardvark }; 

будет на самом деле создать временный от g_aardvark и связываться с этим. Это, конечно, нонсенс, но g ++ 4.8 следовал опубликованному тексту. Стандарт был восстановлен DR 1288, так что ссылка связывается напрямую.

Clang всегда реализовывал разумное поведение, но g ++ не обновлялся до цепочки 4.9.

See here для пояснения со стандартными ссылками и более простой тест.