В п. 5 пункта 12.2 N3126 = 10-0116 говорится, что:
Второй контекст [в котором временные уничтожения уничтожаются в другой точке, чем конец полного выражения], это когдассылка связана с временным.Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего срока жизни ссылки, кроме ...
, а затем следует списокиз четырех особых случаев (ctor-inizializer, ссылочные параметры, возвращаемое значение, новый инициализатор).
Итак (в этой версии) мне кажется, что clang верен, потому что вы привязываете ссылку на подобъект объектавременный.
РЕДАКТИРОВАТЬ
Думая о базовом подобъекте объекта, это также кажется единственным разумным поведением.Альтернатива будет означать выполнение нарезки:
Derived foo();
...
void bar()
{
Base& x = foo(); // not very different from foo().b;
...
}
На самом деле после небольшого эксперимента действительно кажется, что g ++ различает дочерний субобъект и базовый субобъект, но я не понимаю, где этодифференциация производится в стандарте.Ниже приводится тестовая программа, которую я использовал, и там, где отчетливо видна различная обработка двух случаев ... (B
- База, D
- Производная и C
- составная).
#include <iostream>
struct B
{
B()
{ std::cout << "B{" << this << "}::B()\n"; }
B(const B& x)
{ std::cout << "B{" << this << "}::B(const B& " << &x << ")\n"; }
virtual ~B()
{ std::cout << "B{" << this << "}::~B()\n"; }
virtual void doit() const
{ std::cout << "B{" << this << "}::doit()\n"; }
};
struct D : B
{
D()
{ std::cout << "D{" << this << "}::D()\n"; }
D(const D& x)
{ std::cout << "D{" << this << "}::D(const D& " << &x << ")\n"; }
virtual ~D()
{ std::cout << "D{" << this << "}::~D()\n"; }
virtual void doit() const
{ std::cout << "D{" << this << "}::doit()\n"; }
};
struct C
{
B b;
C()
{ std::cout << "C{" << this << "}::C()\n"; }
C(const C& x)
{ std::cout << "C{" << this << "}::C(const C& " << &x << ")\n"; }
~C()
{ std::cout << "C{" << this << "}::~C()\n"; }
};
D foo()
{
return D();
}
void bar()
{
std::cout << "Before calling foo()\n";
const B& b = foo();
std::cout << "After calling foo()\n";
b.doit();
std::cout << "After calling b.doit()\n";
const B& b2 = C().b;
std::cout << "After binding to .b\n";
b2.doit();
std::cout << "After calling b2.doit()\n";
}
int main()
{
std::cout << "Before calling bar()\n";
bar();
std::cout << "After calling bar()\n";
return 0;
}
Вывод, который я получаю с помощью g ++ (Ubuntu / Linaro 4.4.4-14ubuntu5) 4.4.5, равен
Before calling bar()
Before calling foo()
B{0xbf9f86ec}::B()
D{0xbf9f86ec}::D()
After calling foo()
D{0xbf9f86ec}::doit()
After calling b.doit()
B{0xbf9f86e8}::B()
C{0xbf9f86e8}::C()
B{0xbf9f86e4}::B(const B& 0xbf9f86e8)
C{0xbf9f86e8}::~C()
B{0xbf9f86e8}::~B()
After binding to .b
B{0xbf9f86e4}::doit()
After calling b2.doit()
B{0xbf9f86e4}::~B()
D{0xbf9f86ec}::~D()
B{0xbf9f86ec}::~B()
After calling bar()
По моему мнению, это либо ошибка в g ++, либо ошибка в том, что предписывает стандарт c ++если это действительно ожидаемое поведение или возможное приемлемое поведение (но я должен сказать, что я не особо задумывался об этом, это просто ощущение, что что-то не так с этой дифференциацией).