函数调用中临时对象的生命周期
Lifetime of temporaries inside a function call
请看下面的代码示例:
(一)
#include <iostream>
#include <utility>
struct wrapper {
int&& x;
};
void f(wrapper a) { std::cout << std::move(a.x) << std::endl; }
int g() { return 0; }
int main() {
f(wrapper{g()});
}
(B)
#include <iostream>
#include <utility>
struct wrapper {
int&& x;
};
wrapper make_wrapper(int&& x) {
return{ std::move(x) };
}
void f(wrapper a) { std::cout << std::move(a.x) << std::endl; }
int g() { return 0; }
int main() {
f(make_wrapper(g()));
}
这些例子有效吗?也就是说,在 f
的执行完成之前,由 g
创建的临时对象是否仍然存在?当 f
将其参数作为参考时会发生什么?
两个代码示例均有效。
在您的代码中创建的唯一临时对象是从 g()
返回的 int
、从 make_wrapper
返回的 wrapper
和通过聚合创建的 wrapper
-初始化 wrapper{...}
.
所有这些都发生在完整表达式的词法上
f(wrapper{g()});
或
f(make_wrapper(g()));
并且通常临时对象的生命周期结束于创建它们的完整表达式的末尾。因此,在对 f
的调用中,您所有的临时对象都存活到相应行的末尾,并且 none 其中的一些在其使用寿命之外使用。
这条生命周期规则只有少数例外,所有例外都会延长生命周期。实际上,通过聚合初始化将从 g()
返回的临时 int
绑定到 int&&
子对象实际上将临时的生命周期延长到引用的生命周期。
因此
wrapper w{g()};
实际上不会有悬空引用成员,即使在以下语句中也是如此。
请看下面的代码示例:
(一)
#include <iostream>
#include <utility>
struct wrapper {
int&& x;
};
void f(wrapper a) { std::cout << std::move(a.x) << std::endl; }
int g() { return 0; }
int main() {
f(wrapper{g()});
}
(B)
#include <iostream>
#include <utility>
struct wrapper {
int&& x;
};
wrapper make_wrapper(int&& x) {
return{ std::move(x) };
}
void f(wrapper a) { std::cout << std::move(a.x) << std::endl; }
int g() { return 0; }
int main() {
f(make_wrapper(g()));
}
这些例子有效吗?也就是说,在 f
的执行完成之前,由 g
创建的临时对象是否仍然存在?当 f
将其参数作为参考时会发生什么?
两个代码示例均有效。
在您的代码中创建的唯一临时对象是从 g()
返回的 int
、从 make_wrapper
返回的 wrapper
和通过聚合创建的 wrapper
-初始化 wrapper{...}
.
所有这些都发生在完整表达式的词法上
f(wrapper{g()});
或
f(make_wrapper(g()));
并且通常临时对象的生命周期结束于创建它们的完整表达式的末尾。因此,在对 f
的调用中,您所有的临时对象都存活到相应行的末尾,并且 none 其中的一些在其使用寿命之外使用。
这条生命周期规则只有少数例外,所有例外都会延长生命周期。实际上,通过聚合初始化将从 g()
返回的临时 int
绑定到 int&&
子对象实际上将临时的生命周期延长到引用的生命周期。
因此
wrapper w{g()};
实际上不会有悬空引用成员,即使在以下语句中也是如此。