C++ 是";“过早”;有可能毁灭吗?

C++ 是";“过早”;有可能毁灭吗?,c++,destructor,raii,object-lifetime,C++,Destructor,Raii,Object Lifetime,是否保证在返回工作impl()后调用的析构函数?或者在调用工作impl()之前,编译器可以自由地销毁\uuuuuuuuuuuu?如果无法分辨差异,编译器可以自由地执行任何它喜欢的操作。但是如果析构函数有一些程序可见的效果,它总是在work\u impl返回后发生。Expressionwork\u impl(resource)将被执行,结果将被复制到调用方或用作临时命令。然后,将销毁对象 另一方面,不要使用\uuuu或\uuuu作为任何标识符的前缀。它们是为编译器保留的。如果析构函数是非平凡的,则

是否保证在返回
工作impl()
后调用
的析构函数?或者在调用
工作impl()
之前,编译器可以自由地销毁
\uuuuuuuuuuuu

如果无法分辨差异,编译器可以自由地执行任何它喜欢的操作。但是如果析构函数有一些程序可见的效果,它总是在
work\u impl
返回后发生。

Expression
work\u impl(resource)
将被执行,结果将被复制到调用方或用作临时命令。然后,将销毁对象


另一方面,不要使用
\uuuu
\uuuu
作为任何标识符的前缀。它们是为编译器保留的。

如果析构函数是非平凡的,则可能不会调用它 如果代码的其余部分是正确的,那么这是过早的。在里面 未定义行为的情况(例如,具有两个或多个变量的变量名)
当然,也没有保证。

< P>这个程序的行为实际上是未定义的,标识符<代码>代码>代码>保留,我们可以从草案C++标准<代码> 7.64.3保留名称中看到段落2:

如果程序在保留名称的上下文中声明或定义名称,而不是本子句明确允许的名称,则其行为是未定义的

如果我们进一步查看
17.6.4.3.2节
Global names,其中指出:

包含双下划线或以下划线开头,后跟大写字母(2.12)的每个名称都保留给实现以供任何使用

因此,除非编译器文档
\uuuu
可供用户代码自由使用,否则它是保留的

析构函数是隐式调用的

因此,如果该程序没有调用隐式调用的析构函数规则,可以从标准草案第12.4节析构函数第11段(强调我的代码)中获取

-对于程序终止(3.6.3)时具有静态存储持续时间(3.7.1)的构造对象

-对于线程出口处具有线程存储持续时间(3.7.2)的构造对象

-对于具有自动存储持续时间(3.7.3)的构造对象,当创建对象的块退出时(6.7)

-对于建造的临时对象,当临时对象的寿命结束时(12.2)

因此,这意味着自动对象的析构函数将在退出
work()
时被调用,这必须在返回结果后发生。我们可以进一步看到,在中销毁对象的顺序也在
6.6
Jump语句中指定:

从作用域退出时(无论如何完成),在该作用域中构建的具有自动存储持续时间(3.7.3)的对象将按其构建的相反顺序销毁。[注:临时文件见12.2.-尾注]


请注意,包含双下划线或以下划线开头并后跟大写字母的名称是。

包含两个或更多连续下划线的名称保留供实现使用。不要使用它们。@PeteBecker我希望有一种方法可以在不命名的情况下声明一个对象,这样该对象就会在块的末尾被销毁。遗憾的是,未命名的对象被当场销毁。@PeteBecker,它们是否仍然是未定义的行为(或者是否需要某种诊断)?@JamesKanze-不深入细节,是的,我很确定行为是未定义的。无需诊断;一般来说,诊断是不可能的。不,不可能。它们是“保留给实现的”,使用它们的效果是实现定义的,而不是未定义的。在表达式的结果被复制到编译器放置返回值的位置后,它将被销毁。(当然,在这种情况下,RVO可能意味着没有这样的副本。但从概念上讲,它是存在的。)然而,这些标识符的使用是“该条款明确允许的”。17.6.4.3.2表示,这些标识符保留给实施“任何用途”。因此,这些实现可以免费将它们赠送给用户代码。例如,对于实现来说,为用户代码公开这种类型的特定标识符以控制运行库的各个方面是很常见的。如果用户代码不能声明这些符号或包含声明这些符号的标题,它们就不能在兼容代码中使用它们。@Ben这里没有任何迹象表明是这种情况,我也不知道这方面的任何实例,如果您能给我看一些,我会有兴趣看到它们的。我的意思是,
gcc
clang
确实有一些奇怪的角落,因此,如果存在这样的情况,也就不足为奇了。但是它必须被证明是有用的。只是浏览一些随机源文件,在VisualC++运行库中,代码< >代码> TraceDuffgFieldIt/<代码>,以及GLYBC中的代码>“yfFixHoox<”代码。安全总比抱歉好。@Ben well
gcc
Visual C++
是实现,但是用户兰德代码不允许使用这些名称创建变量,尽管一旦实现创建了变量并记录下来,用户兰德代码就可以使用它们。
result_t work(resource_t& resource) {
    lock_t ___(resource);

    return work_impl(resource);
}