在 N3126=10-0116 的 12.2 第 5 段中说:
第二个上下文[其中临时对象在与完整表达式末尾不同的点被销毁]是引用绑定到临时对象时。引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在,除了...
然后是四个特殊情况的列表(ctor-inizializers、引用参数、返回值、新的初始化程序)。
所以(在这个版本中)在我看来,clang 是正确的,因为您将引用绑定到临时的子对象。
编辑
考虑到对象的基本子对象,这似乎也是唯一合理的行为。另一种方法是进行切片:
Derived foo();
...
void bar()
{
Base& x = foo(); // not very different from foo().b;
...
}
实际上,在做了一个小实验之后,g++ 似乎确实区分了成员子对象和基础子对象,但我不明白这种区分在标准中的位置。以下是我使用的测试程序,可以清楚地看到两种情况的不同处理......(B
是 Base,D
是 Derived 并且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++ 标准要求的错误,如果这确实是预期的行为或可能的可接受的行为(但我必须告诉我,我并没有真正考虑过,这是只是感觉这种区分有问题)。