C ++ reordered variables and timers

I am very encouraged by how scoped_lock works, and I was interested in the weather. A similar implementation can be done in time for a certain execution code.

If I say that I am implementing a simple class scoped_timer, which, when building, initiates a timer and stops when it is deleted, and informs about the expiration of time, then will this sample code be correctly calculated

func() { //some code { scoped_timer a; //some code that does not include a } //some code } 

In practice, I guarantee that scoped_time a is created at the beginning and destroyed exactly when it goes beyond. Can the compiler decide to reorder the code so that it does not destroy it exactly at the end of the field or does not build it at the beginning, since there is no dependency on object a ? Are there warranties from the C ++ standard?

thanks

Daniel

+4
source share
1 answer

It is guaranteed that the code will behave as you would like.

This guarantee is important in C ++, because C ++ is not a functional programming language due to the fact that almost any function in C ++ can have side effects (either from the execution thread of the current thread, or from other threads or even other processes, regardless of whether the data is declared volatile ). Because of this, the language specification provides guarantees regarding the sequence of complete expressions.

To combine this with the C ++ 11 standard, there are a number of suggestions that need to be considered together.

The most important point is §1.9:

§1.9 Program execution [intro.execution]

1 The semantic descriptions in this International Standard define a parameterized non-deterministic abstract machine. This International Standard does not require a conformance structure for Implementation. In particular, they do not need to copy or emulate the structure of an abstract machine. Rather, appropriate implementations are required to emulate (only) the observed behavior of the abstract as described below. * (<- the footnote is in the standard itself)

* This provision is sometimes called the “as is” rule, since the implementation is free to ignore any requirement of this International Standard, as long as the result is as if the requirements were met, as far as it can be determined from the observed behavior of the program. For example, the actual need for an implementation does not evaluate part of the expression if it can infer that its value is not used equally and that no side effects affecting the observed behavior of the program are created .

(The bold text is mine.)

This section imposes two important requirements that are relevant to this issue.

  • If an expression can have side effects, it will be appreciated. In your case, the expression scoped_timer a; may have side effects, so it will be appreciated.

  • “... appropriate implementations are required to emulate (only) the observed behavior of an abstract machine, as described below.”, where “below” includes paragraphs 13 and 14 of the same section:

§1.9.13 . Previously segmented is an asymmetric, transitional, pairwise relationship between estimates made by one thread (1.10), which induces a partial order among these estimates. For any two estimates, A and B, if A is sequenced to B, then the execution of A precedes the execution of B. If A is not sequenced to B and B is not sequenced to A, then A and B are not affected. [Please note that optional assessments may overlap. -end note] Scores A and B are indefinitely sequenced when either A is sequenced before B or B is sequenced to A, but it is not defined which. [Note: indefinite sequence of evaluations cannot overlap, but either could be done first. -end note]

§1.9.14 Each calculation of a value and a side effect associated with a full expression is sequenced before each calculation of a value and a side effect associated with the next full expression to be evaluated. * (<- the footnote does not matter here)

Therefore, your expression is scoped_timer a; (which is the full expression) may have side effects and will be evaluated; therefore, the calculation of a will be sequenced before any of the following statements in the block.

As for destroying object a , this is simpler.

§3.7.3.3 If a variable with automatic storage duration has initialization or a destructor with side effects, this should not be destroyed until the end of its block, and it will not be eliminated as optimization, even if it is not used, except that the class is an object or its copy / movement can be eliminated as specified in 12.8.

This makes it clear that the destructor will not be called until the block exits.

ADD . And to confirm that all blocking level variables are destroyed (and their destructor is called) at the end of the block area, here it is in the C ++ 11 standard:

§3.7.3.1 Scope variables explicitly declared by the register or not explicitly declared static or external have automatic storage duration. Storage for these objects remains until the block in which they are located exits.

§3.7.3.2 [Note. These variables are initialized and destroyed as described in 6.7. -end note]

... and the aforementioned §6.7:

§6.7.2 Variables with automatic storage duration (3.7.3) are initialized each time their expression-expression is executed. Variables with automatic storage time declared in the block are destroyed upon exiting the block (6.6).

A block is defined as all code between a pair of curly braces {} here:

§ 6.3.1 . So that several operators can be used where expected, a compound operator is provided (also, accordingly, called a "block").

 compound-statement: { statement-seq } statement-seq: statement statement-seq statement 

The compound operator defines the area of ​​the block (3.3).

Note. The compount-statement (etc.) section takes time to get used to, but the important thing is that the open curly bracket { and the closing curly bracket } actually means the literal open curly bracket and close the curly braces in the code. This is the exact place in the C ++ 11 standard where the block region is defined as a sequence of statements between curly braces.

Combining fragments: since the standard, as mentioned above, says The storage for these entities lasts until the block in which they are created exits and that Variables with automatic storage duration declared in the block are destroyed on exit from the block , you are sure that the object a in your question (and ANY block-level object) will last until the end of the block is destroyed and its destructor will be called upon exit from the block.

+5
source

All Articles