函数参数不会在该函数退出时销毁

斜角Lemelisk

我很确定,应该在相应函数的出口处调用函数参数的析构函数。考虑C ++ 11标准的5.2.2p4:

[...]参数的生存期在定义它的函数返回时结束。[...]

但是,让我们尝试以下代码:

#include <iostream>
using namespace std;

struct Logger {
    Logger(int) { cout << "Construct " << this << '\n'; }
    Logger(const Logger&) { cout << "Copy construct " << this << '\n'; }
    ~Logger() { cout << "Destruct " << this << '\n'; }
};

int f(Logger)
{
    cout << "Inside f\n";
    return 0;
}

int main()
{
    f(f(f(10)));
}

用gcc或clang编译后,输出将如下所示:

Construct 0x7fffa42d97ff
Inside f
Construct 0x7fffa42d97fe
Inside f
Construct 0x7fffa42d97fd
Inside f
Destruct 0x7fffa42d97fd
Destruct 0x7fffa42d97fe
Destruct 0x7fffa42d97ff

如我们所见,所有三个参数仅在最后一个函数调用完成后才被销毁。这是正确的行为吗?

用户名

要详细说明,现在可以在注释中找到:

给定int f(Logger);,当您编写时:

f(10);

这(从概念上)构造一个临时Logger对象,从该临时对象构造函数参数,调用该函数,销毁该函数参数,最后销毁该临时对象。

当你写:

f(f(10));

这(从概念上)构造一个临时Logger对象,从该临时对象构造函数参数,调用该函数,销毁该函数参数,Logger使用第一个函数调用的结果构造一个新的临时对象,从临时对象构造函数参数,调用函数,销毁函数参数,最后销毁两个临时对象。

我会尽量避免写出来f(f(f(10)));

现在,可以省略这两个临时对象:

当满足某些条件时,即使该对象的复制/移动构造函数和/或析构函数具有副作用,也允许实现忽略类对象的复制/移动构造。在这种情况下,实现将忽略的复制/移动操作的源和目标视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象本来应该以较晚的时间发生。没有优化就销毁。在以下情况下允许复制/移动操作的这种省略,称为复制删除(可以合并以消除多个副本):

  • ...

  • 当尚未绑定到引用(12.2)的临时类对象将被复制/移动到具有相同cv-unqualtype类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制/移动操作省略的副本/移动的

  • ...

由于函数参数和临时对象具有相同的类型,因此允许编译器将它们视为相同的对象。临时对象将在最后阶段被销毁,因此该参数的寿命不会发挥作用。

但是,当执行复制省略时,例如,因为您未配置编译器,或者因为首先没有要复制的副本(请参见下文),那么当您说函数参数应该删除时,确实必须销毁它们。在所有符合C ++ 11的实现中,在第二个函数调用开始之前,您必须先看到“ Destruct(...)”。

使用花括号可以构造一个没有临时参数的参数:您可以将调用重新处理为

f({f({f({10})})});

这里,每个参数都是列表初始化的,在这种情况下,它不涉及临时对象,也没有要删除的副本。在所有符合C ++ 11的实现中,无论是否有任何命令行选项,这都必须在函数f返回之前立即销毁函数参数,而实际上,编译器不执行此操作是一个需要解决的问题他们不符合C ++ 11。f-felide-constructors

但是,它并不是那么简单:CWG 1880年的内容如下:

WG决定不指定在调用之后还是在调用所属的完整表达式的结尾销毁参数对象。

这将完全允许编译器执行以下操作:在完整表达式结束后,最后一个f返回之后,可以销毁参数C ++ 11的确切文字文本不是当前编译器实现的。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

区域监视当前位置不会在退出时通知

来自分类Dev

Javascript函数不会在返回时中断吗?

来自分类Dev

ajax成功函数不会在成功时重定向

来自分类Dev

构造函数抛出时,数组不会在此处释放,对吗?

来自分类Dev

Python进程不会在GTK循环退出时退出

来自分类Dev

ObservableArray不会在函数外部反映其值

来自分类Dev

在函数内部更改指针不会在函数外部反映

来自分类Dev

事务注释不会在退出时保存

来自分类Dev

Nodemailer不会在退出时发送邮件

来自分类Dev

Javascript函数不会在页面加载时执行

来自分类Dev

PHP变量不会在函数外部更改

来自分类Dev

使用“断言”从一个函数运行python中的所有测试文件,而不会在测试失败时退出“ for循环”

来自分类Dev

Thunar不会在退出时保存设置

来自分类Dev

该函数不会在Vue生命周期挂钩上加载,但在通过V-on调用时会加载

来自分类Dev

减速器的参数不会在分派时更新

来自分类Dev

向量层属性不会在函数调用中加载

来自分类Dev

将值传递给函数时,苗条值不会在屏幕上更新

来自分类Dev

React不会在map函数中渲染元素

来自分类Dev

JavaScript函数不会在div悬停时更改图像

来自分类Dev

Poco AsyncChannel不会在派生进程退出时退出

来自分类Dev

函数不会在unityscript中运行

来自分类Dev

C#返回不会退出该函数

来自分类Dev

jQuery $('input [name =“”]')。change(除非Chrome浏览器出现未捕获的错误,否则该函数不会在Chrome中启动

来自分类Dev

ng-click不会在ionic中调用该函数吗?

来自分类Dev

将参数函数指定为输入,而不会在 Scala 中过度限制它们

来自分类Dev

使用带有函数参数的 .bind() 时,事件不会在 mousedown 上更新

来自分类Dev

delete 不会在函数结束时释放内存

来自分类Dev

在函数中修改的对象不会在函数外被修改

来自分类Dev

当我访问子元素时,函数不会在循环后继续

Related 相关文章

  1. 1

    区域监视当前位置不会在退出时通知

  2. 2

    Javascript函数不会在返回时中断吗?

  3. 3

    ajax成功函数不会在成功时重定向

  4. 4

    构造函数抛出时,数组不会在此处释放,对吗?

  5. 5

    Python进程不会在GTK循环退出时退出

  6. 6

    ObservableArray不会在函数外部反映其值

  7. 7

    在函数内部更改指针不会在函数外部反映

  8. 8

    事务注释不会在退出时保存

  9. 9

    Nodemailer不会在退出时发送邮件

  10. 10

    Javascript函数不会在页面加载时执行

  11. 11

    PHP变量不会在函数外部更改

  12. 12

    使用“断言”从一个函数运行python中的所有测试文件,而不会在测试失败时退出“ for循环”

  13. 13

    Thunar不会在退出时保存设置

  14. 14

    该函数不会在Vue生命周期挂钩上加载,但在通过V-on调用时会加载

  15. 15

    减速器的参数不会在分派时更新

  16. 16

    向量层属性不会在函数调用中加载

  17. 17

    将值传递给函数时,苗条值不会在屏幕上更新

  18. 18

    React不会在map函数中渲染元素

  19. 19

    JavaScript函数不会在div悬停时更改图像

  20. 20

    Poco AsyncChannel不会在派生进程退出时退出

  21. 21

    函数不会在unityscript中运行

  22. 22

    C#返回不会退出该函数

  23. 23

    jQuery $('input [name =“”]')。change(除非Chrome浏览器出现未捕获的错误,否则该函数不会在Chrome中启动

  24. 24

    ng-click不会在ionic中调用该函数吗?

  25. 25

    将参数函数指定为输入,而不会在 Scala 中过度限制它们

  26. 26

    使用带有函数参数的 .bind() 时,事件不会在 mousedown 上更新

  27. 27

    delete 不会在函数结束时释放内存

  28. 28

    在函数中修改的对象不会在函数外被修改

  29. 29

    当我访问子元素时,函数不会在循环后继续

热门标签

归档