【发布时间】:2021-09-20 21:48:34
【问题描述】:
当一个引用被另一个延长临时生命周期的引用初始化时,这个新引用不会扩展任何东西。
但是当强制 RVO 阻止引用被复制时会发生什么?
考虑这个例子:run on gcc.godbolt.org
#include <iostream>
struct A
{
A() {std::cout << "A()\n";}
A(const A &) = delete;
A &operator=(const A &) = delete;
~A() {std::cout << "~A()\n";}
};
struct B
{
const A &a;
};
struct C
{
B b;
};
int main()
{
[[maybe_unused]] C c{ B{ A{} } };
std::cout << "---\n";
}
在 GCC 下会打印出来
A()
---
~A()
但在 Clang 下结果是
A()
~A()
---
哪个编译器是正确的?
乍一看,GCC 做了正确的事。但在这个例子中:
C foo()
{
return { B{ A{} } };
}
int main()
{
[[maybe_unused]] C c = foo();
std::cout << "---\n";
}
A 的生命周期肯定不能扩展到函数之外(并且两个编译器都同意这一点)。
既然这个 sn-p 应该与第一个具有相同的 RVO,那么行为不应该相同吗?因此 Clang 的行为似乎更加一致。
【问题讨论】:
-
fyi - 有趣的尝试是添加
-O3并注意两个编译器都不会创建对象而只打印输出。至少两者的顺序没有改变。 -
fyi2 - 为
B和C添加了析构函数工具,我现在更加困惑gcc.godbolt.org/z/YqdYn95xP -
@RichardCritten
B是直接在c中构造的,因为是RVO,所以说得通。 -
@j6t 为什么不呢?我们用一个临时值初始化一个引用。当不涉及 RVO 时,它确实会发生 here。
-
我的意思是忘记 [class.temporary]/3,由于 [class.temporary]/(6.2) 从函数返回时不会延长临时对象的生命周期。
标签: c++ language-lawyer return-value-optimization