嵌套函数调用中临时实参的生命周期及C++23代码验证问询
C++23嵌套函数调用中临时实参的生命周期验证
我们来分析C++23标准下嵌套函数调用里临时实参的生命周期,先看示例代码:
#include <print> #include <string> struct X { std::string tag; ~X() { std::println("X::~X() - {}", tag); } }; X f(const X& x) { std::println("f() - {}", x.tag); return {x.tag + "!"}; } int main() { f(f({"x"})); }
假设输出的正确性验证
你给出的假设输出是正确的:
f() - x f() - x! X::~X() - x!! X::~X() - x! X::~X() - x
对应的核心规则如下:
绑定到引用参数的临时对象生命周期延长至完整表达式结束:
绑定到函数调用中引用参数的临时对象,会持续到包含该调用的完整表达式执行完毕。
最内层的临时对象{"x"}绑定到内层f的const X&参数,它的生命周期不会在f返回后结束,而是要等整个f(f({"x"}))完整表达式执行完毕才销毁。临时对象按创建逆序销毁:
生命周期未被延长到创建它的完整表达式之外的临时对象,其销毁顺序早于所有在同一完整表达式中更早创建的临时对象。
临时对象的创建顺序为:{"x"}→ 内层f返回的x!→ 外层f返回的x!!,因此销毁顺序是逆序:x!!最先销毁,接着是x!,最后是x,与输出完全匹配。
值参数的特殊情况
如果将f()的声明改为X f(X x),你给出的输出是符合标准允许的一种情况:
f() - x X::~X() - x f() - x! X::~X() - x! X::~X() - x!!
对应的规则说明:
- 值参数的生命周期由实现定义:
参数的生命周期是实现定义的,既可以在函数返回时结束,也可以在包含该调用的完整表达式结束时结束。
这个输出对应编译器选择在函数返回时立即销毁值参数的情况:内层f的参数x在函数返回后就被销毁,因此出现了中间的X::~X() - x输出。当然,也有编译器会让值参数的生命周期延续到完整表达式结束,此时输出会和引用参数的情况类似,这同样符合标准要求。
内容的提问来源于stack exchange,提问作者Valentin Milea
相关产品推荐
相关产品推荐

