【问题标题】:When passing a class by-value, does the caller or callee call the destructor?按值传递类时,调用者或被调用者是否调用析构函数?
【发布时间】:2019-10-28 06:20:29
【问题描述】:

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

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
}

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

  1. 被调用者(即foo)在返回之前对其所有按值参数调用析构函数,然后调用者释放内存(通过将其从堆栈中弹出)。
  2. 被调用者不做任何事情,调用者(即bar)在foo(p)调用结束的序列点之前的所有临时对象上调用析构函数。

【问题讨论】:

  • 作为一般规则 - 创造者毁灭。
  • 有需要知道的理由吗?如果只是好奇,请查看为您的平台生成的程序集。
  • 我想知道你为什么问这个问题。如果您说“只是为了知识”-我可以接受。我很确定临时销毁是在调用方完成的。但是,依靠这个可以解决什么问题呢? (并不是说我会依赖这个。);-)
  • @Eljay 这并不能真正回答问题。看到某件事在您的平台上以特定方式发生并不能保证所有符合要求的实现都会做同样的事情。

标签: c++ language-lawyer destructor


【解决方案1】:

标准在 [expr.call]/4 中回答了这个问题,详细程度令人惊讶:

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

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

【讨论】:

  • 为了完整性,你不应该提到 c-functions 和 c-structs (no\trivial destructors),它们也是 C++ 的一部分吗?那些通常在被调用者中进行堆栈清理。
  • 那么,析构函数是在函数执行后立即调用,还是由于在调用函数的上下文中,所以在调用函数退出时销毁?
  • @Chipster 也在该段中:“参数的生命周期是在定义它的函数返回时结束还是在封闭的完整表达式结束时结束,这是实现定义的。” /跨度>
【解决方案2】:

调用者销毁它。见https://en.cppreference.com/w/cpp/language/lifetime。引用:

所有临时对象都作为评估的最后一步被销毁 (词法上)包含它们所在点的完整表达式 已创建,如果创建了多个临时对象,则它们是 破坏的顺序与创造的顺序相反。

也将此作为一般规则 - 谁创造,谁破坏。通常以相反的顺序。

【讨论】:

    【解决方案3】:

    只要对象的生命周期结束,就会调用析构函数,包括

    范围结束,用于具有自动存储持续时间的对象和 通过绑定到引用来延长寿命的临时对象

    所以bar 是复制对象的所有者,将对复制的对象调用dtorCppreference

    【讨论】:

      【解决方案4】:

      调用者和被调用者的想法对我来说似乎是错误的。你应该在这里想到scopes

      在创建函数堆栈的那一刻,foo 中的对象 P x 开始存在,该对象将被“创建”。因此,对象最终将通过离开作用域被删除,在您的情况下,离开函数。

      因此,在引入新对象的函数内部具有局部作用域,然后将该作用域留在同一个函数中,这在理论上没有区别。

      编译器能够“查看”您的对象是如何使用的,尤其是修改后的对象,并且可以通过内联函数也跳过“临时”对象的创建,只要代码表现得“好像”编写。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多