When I have a loop and inside this loop create a new stack variable (not allocating it on the heap and variable holding it declared inside the loop body), is the destructor of this object guaranteed to be called before the next iteration starts, or might loop unrolling by the compiler change something about that?
Is the destructor of a local object inside a loop guaranteed to be called before the next iteration?
-
1Loop unrolling *per se* won't change the order of execution. However, loop ***parallelization*** could do this. – Adrian Mole Dec 06 '19 at 12:17
-
4Does this answer your question? [C++ - If an object is declared in a loop, is its destructor called at the end of the loop?](https://stackoverflow.com/questions/10388108/c-if-an-object-is-declared-in-a-loop-is-its-destructor-called-at-the-end-of) – Matz Dec 06 '19 at 12:21
5 Answers
From n4800
:
§6.3.3 Block Scope:
A name declared in a block (8.3) is local to that block; it has block scope. Its potential scope begins at its point of declaration (6.3.2) and ends at the end of its block. A variable declared at block scope is a local variable.
§10.3.6 Destructors:
A destructor is invoked implicitly [...] when the block in which an object is created exits (8.7)
§4.1.1 Abstract machine:
This provision is sometimes called the “as-if” rule, because an implementation is free to disregard any requirement of this document as long as the result is as if the requirement had been obeyed, as far as can be determined from the observable behavior of the program.
[Emphasis mine]
So, yes. Your variable goes out of scope at the end of the loop (which is a block) and hence its destructor is called as far as anyone observing the behavior of the program can tell.

- 27,315
- 3
- 37
- 54
-
1
-
Compilers are allowed to reorder operations that don't impact function. The destructor could be called halfway through the next loop. – stark Dec 06 '19 at 12:31
-
2@stark What allows them to do this is the as-if rule. The standard only specifies behavior of the abstract machine. Not sure if it's necessary to go into all that detail in answers here. – Max Langhof Dec 06 '19 at 12:36
-
question is if the standard specifies that the destructor is called immediately before the next loop starts or not. If it's not specified, then I guess the compiler would be allowed to do it without violating the as-if rule, since it's still behaving as defined, no? – matthias_buehlmann Dec 06 '19 at 12:39
-
2@stark This is, IMO, irrelevant to the question. You may as well say that destructors may be inlined, and therefore not `call`ed at all. Or, if they effectively (as-if rule) do nothing, there may be no assembly for such destructors generated. – Daniel Langr Dec 06 '19 at 12:41
-
Suppose the destructor writes to cout. What in the standard guarantees when that happens? – stark Dec 06 '19 at 12:54
-
2@stark See [What exactly is the “as-if” rule?](https://stackoverflow.com/q/15718262/580083). – Daniel Langr Dec 06 '19 at 12:56
-
1The as-if rule only applies to defined operations. I'm asking where this is defined. – stark Dec 06 '19 at 13:00
-
2@stark Where is defined _what_? Note that this discussion is off-topic to the question. You may ask another separate question about this problem. – Daniel Langr Dec 06 '19 at 13:01
-
It's exactly on topic actually. If it's not clearly defined when the destructor gets called, then the 'as-if' rule can't be used to explain why loop unrolling for example couldn't change the order of things that are happening. – matthias_buehlmann Dec 06 '19 at 13:43
-
@user1282931 I cannot quote the standard (although I am sure the standard is quite clear on the matter), but destructors getting called deterministically is what makes C++ C++. Do you really doubt that it is possible to be sure when a destructor is called? – 463035818_is_not_an_ai Dec 06 '19 at 14:57
-
1
Yes. It's easier to visualize when you consider the "blocks" in which you declare a variable, i.e. between which pair of braces. The loop is a block in itself, and when it reaches the closing bracket, before the next iteration, all destructors of automatic storage variables declared in the loop are called.
might loop unrolling by the compiler change something about that?
As a rule of thumb don't think about what the compiler will optimize, because it still needs to guarantee the behaviour of your program, no matter what it does to optimize it. In that case, loop unrolling won't change anything to that effect if it happens.

- 12,588
- 4
- 53
- 84
-
2+1 for the rule of thumb, when writing code one should not worry about compiler internals. Was going to add something in the same spirit to my answer, but now its already there – 463035818_is_not_an_ai Dec 06 '19 at 12:19
-
copy-elision and RVO change the program behavior, isn't it? – Jean-Baptiste Yunès Dec 06 '19 at 12:21
-
@Jean-BaptisteYunès They can potentially, however, the standard allows them too per `[class.copy.elision] ` – ChrisMM Dec 06 '19 at 12:28
-
Not just _pair of braces_. You can write `for(...) X x{};` and the `x` object will be constructed+destructed in each iteration. [Live demo](https://wandbox.org/permlink/0x9fc2u4a8AVKazQ). A relevant Standard section is [stmt.iter/2](http://eel.is/c++draft/stmt.iter#2). – Daniel Langr Dec 06 '19 at 12:38
-
@DanielsaysreinstateMonica As per §9.5.2 `[stmt.iter]` it's purely equivalent (emphasis mine): "If the substatement in an iteration-statement is a single statement and not a compound-statement, **it is as if it was rewritten to be a compound-statement containing the original statement.**". In essence, with or without the braces for a single statement means exactly the same thing and the braces are implicit. I omitted it for clarity. – JBL Dec 06 '19 at 12:43
The destructor is called for every iteration. Thus in some cases it’s faster to declare a variable outside the loop instead of in the loop. Assuming the following case:
std::string temp;
for(int i = 0; i < 10; ++i){
temp = arr[i];
doSomething(temp);
}
The destructor is not called when using the loop is executed. It just overrides temp
.
But if you use std::string temp = arr[i]
the constructor and destructor is called for each iteration.
I think this adds a bit runtime in case you have a loop that is executed very often.

- 182
- 1
- 11
-
note that destructors getting called or not is not just a question of performance. When you have a RAII type, you specifically want the destructor to be called on every iteration – 463035818_is_not_an_ai Dec 06 '19 at 13:08
-
not sure that's true. Doesn't the destructor of the contents 'temp' is holding from the previous iteration get called right when temp gets reassigned with the new value? – matthias_buehlmann Dec 06 '19 at 13:45
-
I am not a 100% sure either. Correct my answer if you found something wrong. :) – SchnJulian Dec 06 '19 at 14:06
Of course dtor is called at the end of the iteration and loop unrolling should not modify this behavior, as any other optimisation (an optimisation should not modify the program behavior), except some kind of RVO and alike which may eliminate some semantically spurious object creations.

- 34,548
- 4
- 48
- 69