当前位置:  开发笔记 > 编程语言 > 正文

函数返回值是自动对象,因此可以保证被破坏吗?

如何解决《函数返回值是自动对象,因此可以保证被破坏吗?》经验,为你挑选了3个好方法。

在[except.ctor]中,标准(N4140)保证:

...自从输入try块以来构造的所有自动对象都会调用析构函数...

但是在下面的例子中,空输出证明函数的返回值foo没有被破坏,尽管它已被构造.使用g ++(5.2.1)和clang ++(3.6.2-1)以及选项编译-O0 -fno-elide-constructors -std=c++14.

struct A { ~A() { cout << "~A\n"; } };

struct B { ~B() noexcept(false) { throw 0; } };

A foo() {
  B b;
  return {};
}

int main() {
  try { foo(); }
  catch (...) { }
}

这是g ++和clang ++中的错误,还是函数返回值不被视为自动对象,还是C++语言中的循环漏洞?

在[stmt.return],[expr.call]或[dcl.fct]中都没有找到一个明确的语句,函数返回值是否被视为自动对象.我找到的最接近的提示是6.3.3 p2:

......退货声明可能涉及临时物体的构造和复制或移动......

和5.2.2 p10:

如果结果类型是左值引用类型或对函数类型的右值引用,则函数调用是左值;如果结果类型是对象类型的右值引用,则为xvalue,否则为prvalue.

TartanLlama.. 45

函数返回值被认为是临时值,并且在销毁本地之前对返回值的构造进行排序.

不幸的是,标准中没有详细说明.有一个开放的缺陷描述了这一点并提供了一些解决问题的措辞

[...]具有void类型的操作数的return语句只能在返回类型为cv void的函数中使用.带有任何其他操作数的return语句只能在返回类型不是cv void的函数中使用; return语句初始化要从操作数复制初始化(8.5 [dcl.init])返回的对象或引用.[...]

返回实体的复制初始化在由return语句的操作数建立的全表达式结束时临时销毁之前进行排序,然后在本地变量的销毁之前对其进行排序(6.6 [stmt.包含return语句的块的跳转).

由于函数返回值是临时值,因此destructors are invoked for all automatic objects在帖子开头的引用中不包括它们.但是,[class.temporary]/3说:

[...]临时对象被破坏,作为评估(词法)包含创建它们的点的完整表达式的最后一步.即使该评估以抛出异常结束,也是如此.[...]

所以我认为你可以认为这是GCC和Clang中的一个错误.

不要从析构函数中抛出;)



1> TartanLlama..:

函数返回值被认为是临时值,并且在销毁本地之前对返回值的构造进行排序.

不幸的是,标准中没有详细说明.有一个开放的缺陷描述了这一点并提供了一些解决问题的措辞

[...]具有void类型的操作数的return语句只能在返回类型为cv void的函数中使用.带有任何其他操作数的return语句只能在返回类型不是cv void的函数中使用; return语句初始化要从操作数复制初始化(8.5 [dcl.init])返回的对象或引用.[...]

返回实体的复制初始化在由return语句的操作数建立的全表达式结束时临时销毁之前进行排序,然后在本地变量的销毁之前对其进行排序(6.6 [stmt.包含return语句的块的跳转).

由于函数返回值是临时值,因此destructors are invoked for all automatic objects在帖子开头的引用中不包括它们.但是,[class.temporary]/3说:

[...]临时对象被破坏,作为评估(词法)包含创建它们的点的完整表达式的最后一步.即使该评估以抛出异常结束,也是如此.[...]

所以我认为你可以认为这是GCC和Clang中的一个错误.

不要从析构函数中抛出;)


我发现gcc和clang已经有多年来一直存在这个bug,所以我不希望他们很快就会解决这个问题:[gcc](https://gcc.gnu.org/bugzilla/show_bug.cgi? id = 33799),[clang](https://llvm.org/bugs/show_bug.cgi?id=12286).

2> Sebastian Re..:

这是一个错误,一次,MSVC实际上是正确的:它打印"~A".


你能不能添加对标准的引用,证明函数返回值被认为是一个自动对象,或者哪个证明它确实是gcc和clang中的错误?
@MSalters."还能做什么呢?" 对,我有同样的感受.但它不是证据.我更愿意确认并查看标准中的相关段落.我们从经验中知道C++语言有很多惊喜.

3> AC Voltage..:

我修改了你的代码,我认为现在从输出我们可以看到A没有被破坏.

#include

using namespace std;

struct A {
    ~A() { cout << "~A\n"; }
    A() { cout << "A()"; }
};

struct B {
    ~B() noexcept( false ) { cout << "~B\n"; throw(0); }
    B() { cout << "B()"; }
};

A foo() {
    B b;
    return;
}

int main() {
    try { foo(); }
    catch (...) {}
}

输出是:

B()A()〜乙

所以是的,它可能是一个错误.

推荐阅读
小妖694_807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有