传递类按值时,调用方或被调用方是否调用析构函数?

Gre*_*ory 10 c++ destructor language-lawyer

假设我有以下(经过精简的)代码:

class P { P(); P(const P&); ~P(); }

void foo(P x) {
  ...
}

void bar() {
  P p{};
  foo(p); // compiler uses P::(const P&) to construct the value for x
  ...
  // compiler calls P::~P() on p
}
Run Code Online (Sandbox Code Playgroud)

编译器必须创建的副本p才能调用foo,因此调用者在调用之前会调用副本构造函数。我的问题是,谁负责破坏这个创建的对象?似乎有两个有效的选择:

  1. 被调用方(即foo)在返回之前使用其所有按值参数调用析构函数,然后调用方释放内存(通过将其弹出堆栈)。
  2. The callee doesn't do anything, and the caller (i.e. bar) calls the destructor on all of the temporaries before the sequence point at the end of the foo(p) call.

Bri*_*ian 13

The standard answers this question in [expr.call]/4, with a surprising amount of elaboration:

...每个参数的初始化和销毁​​发生在调用函数的上下文中。[ 示例:在调用函数的调用点检查构造函数,转换函数或析构函数的访问。如果函数参数的构造函数或析构函数引发异常,则在调用函数的范围内开始搜索处理程序;特别是,如果被调用的函数具有一个带有可以处理异常的处理程序的function-try-block(第18条),则不考虑该处理程序。—结束示例 ]

换句话说,析构函数由调用函数调用。

  • @Chipster也在该段中:“参数的生命周期是在定义它的函数返回时结束还是在封闭的完整表达式结束时结束,是由实现定义的。” (2认同)