我非常喜欢scoped_lock的工作方式,并且想知道天气可以做类似的实现来计算特定的执行代码
如果说我实现了一个简单的类scoped_timer,它在构造时启动一个计时器并在删除时停止并报告已经过的时间,那么这个示例代码是否会正确计时
func()
{
//some code
{
scoped_timer a;
//some code that does not include a
}
//some code
}
Run Code Online (Sandbox Code Playgroud)
在实践中,我保证scoped_time a在开始时构造并在它超出范围时完全破坏.编译器是否可以决定对代码进行重新排序,以免在范围结束时完全破坏代码或在开头构造代码,因为不依赖于object a?C++标准有保证吗?
谢谢
丹尼尔
保证代码可以按照您的意愿运行.
这种保证在C++中很重要,因为C++不是函数式编程语言,因为C++ 中的几乎任何函数都可能产生副作用(来自当前线程的执行流程,或来自其他线程甚至其他进程) ,无论数据是否被声明为volatile).因此,语言规范保证了完整表达式的排序.
要从C++ 11标准中将它拼凑在一起,必须同时考虑许多条款.
最重要的条款是§1.9:
§1.9程序执行[intro.execution]
1本国际标准中的语义描述定义了参数化的非确定性抽象机器.本国际标准对符合实施的结构没有要求.特别是,它们不需要复制或模拟抽象机器的结构.相反,需要符合实现来模拟(仅)抽象机器的可观察行为,如下所述.*(< - 脚注在标准本身)
*这项规定有时被称为"假设"规则,因为只要结果好像已经遵守了要求,只要可以从可观察的数据中确定,实施就可以自由地忽视本国际标准的任何要求.该计划的行为.例如,实际实现不需要评估表达式的一部分,如果它可以推断出它的值没有被使用,并且没有产生影响程序的可观察行为的副作用.
(文本的粗体是我的.)
本条款规定了与此问题相关的两个重要要求.
如果表达式可能有副作用,则会对其进行评估.在您的情况下,表达式scoped_timer a;可能有副作用,因此将进行评估.
" ......符合要求的实现需要模仿(仅)抽象机器的可观察行为,如下所述. ","下方"包括同一部分的第13和14条:
§1.9.13之前的序列是由单个线程(1.10)执行的评估之间的不对称,传递,成对关系,它在这些评估中引起部分顺序.给定任何两个评估A和B,如果A在B之前被排序,那么A的执行应该在B的执行之前.如果A在B之前没有排序,而B在A之前没有排序,那么A和B是未排序的.[注意:未经测试的评估的执行可能会重叠.-end note]评估A和B是不确定的顺序,当A在A之前测序或B在A之前测序,但未指定哪一个.[注意:不确定顺序的评估不能重叠,但可以先执行. - 尾注]
§1.9.14在每个值计算和与要评估的下一个完整表达式相关的副作用之前,对与全表达式相关的每个值计算和副作用进行排序.*(< - 此处的脚注无关紧要)
因此,您的表达式scoped_timer a;(这是一个完整的表达式)可能有副作用并将被评估; 因此a,在块中的任何以下语句之前,将对值的计算进行排序.
关于物体的破坏a,这更简单.
§3.7.3.3如果具有自动存储持续时间的变量具有初始化或具有副作用的析构函数,则不应在其块结束之前销毁它,也不应将其作为优化消除,即使它看起来是未使用的,除非可以按照12.8中的规定消除类对象或其复制/移动.
这清楚表明在块退出之前不会调用析构函数.
ADDENDUM为了确认在块作用域结束时所有块级变量都被销毁(以及它们的析构函数被调用),这里是C++ 11标准:
§3.7.3.1块范围变量显式声明寄存器或未显式声明为static或extern具有自动存储持续时间.这些实体的存储将持续到创建它们的块为止.
§3.7.3.2 [注:如6.7所述,这些变量被初始化和销毁. - 尾注]
......以及上述§6.7:
§6.7.2每次执行声明语句时,都会初始化具有自动存储持续时间(3.7.3)的变量.块中声明的具有自动存储持续时间的变量在从块(6.6)退出时被销毁.
该块被定义为一对花括号之间的所有代码{}:
§6.3.1因此,如果需要一个语句,可以使用复合语句(也称为"块").
Run Code Online (Sandbox Code Playgroud)compound-statement: { statement-seq } statement-seq: statement statement-seq statement复合语句定义块范围(3.3).
注意:compount-statement(etc)部分需要一段时间才能习惯,但重要的是,在这里,开放花括号{和近花括号}实际上意味着代码中的文字开放花括号和紧密花括号.这是C++ 11标准中的确切位置,其中block范围被定义为花括号之间的语句序列.
将各个部分组合在一起:因为标准,如上所述,The storage for these entities lasts until the block in which they are created exits并且Variables with automatic storage duration declared in the block are destroyed on exit from the block您可以确信,a您的问题中的对象(以及任何块级对象)将持续到块的结尾,并且将被销毁并具有其块退出时调用析构函数.