В 12.2 пункт 5 N3126=10-0116 сказано, что:
Второй контекст [в котором временные объекты уничтожаются не в конце полного выражения] — это когда ссылка привязана к временному объекту. Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего времени жизни ссылки, за исключением...
а затем следует список из четырех особых случаев (ctor-инициализаторы, ссылочные параметры, возвращаемое значение, новый инициализатор).
Так что (в этой версии) мне кажется, что 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++, если это действительно ожидаемое поведение или возможное приемлемое поведение (но я должен сказать, что я действительно не думал об этом много, это просто ощущение, что что-то не так с этой дифференциацией).
person
6502
schedule
16.04.2011
a.b
. - person Johannes Schaub - litb   schedule 17.04.2011