为何C++函数参数的析构函数不在函数结束时调用,而是在完整表达式结束时?
C++函数参数的析构时机疑问与解释
示例代码
#include <iostream> struct A { int n = 0; A() { std::cout << "A()" << std::endl; } A(const A&) { std::cout << "A(const A&)" << std::endl; } ~A() { std::cout << "~A()" << std::endl; } }; int f(A a) { std::cout << "f()" << std::endl; return 1; } int main() { A a; std::cout << f(a) << " was returned from f(A)" << std::endl; std::cout << "leaving main..." << std::endl; }
预期输出
A() A(const A&) f() ~A() 1 was returned from f(A) leaving main... ~A()
实际输出
A() A(const A&) f() 1 was returned from f(A) leaving main... ~A()
行为解释
你的核心困惑在于函数参数的析构时机——按照直觉,函数返回时参数应该立即销毁,但实际输出里参数的析构被延迟到了main中输出完返回值之后。
这是因为C++标准允许函数参数的生命周期延长到包含该函数调用的完整表达式结束。这里std::cout << f(a) << ...是一个完整表达式,直到这个表达式执行完毕(也就是输出完整个字符串之后),f的参数a才会被销毁。
不过要明确的是,这种延迟析构完全不影响你提到的未定义行为:
A* g(A a) { std::cout << "g()" << std::endl; return &a; } // 以下代码仍为未定义行为 std::cout << g(a)->n << std::endl;
即便参数的析构时机被延迟,标准依然规定函数返回后,参数的生命周期已经结束(或者说,程序不能再通过返回的指针/引用访问该参数),任何对该对象的访问都是未定义行为——编译器只是允许延迟销毁,但不保证对象依然可用。
简单来说:函数参数的析构时机可以是函数返回时,也可以是包含函数调用的完整表达式结束时,具体由编译器决定,但无论哪种情况,函数返回后都不能再访问该参数对象。
内容的提问来源于stack exchange,提问作者Lassie
相关产品推荐
相关产品推荐

