It's worth noting that creating or destroying an integer on the stack only involves incrementing or decrementing a pointer. And the compiler could in principle move this bit around, so that this:
1 2 3 4 5 6 7
for ( int i = 0; i < 10; i++ )
{
for ( int j = 0; j < 10; j++ )
{
blah
}
}
actually becomes this (ignoring lexical scope):
1 2 3 4 5 6 7 8 9
int i;
int j;
for ( i = 0; i < 10; i++ )
{
for ( j = 0; j < 10; j++ )
{
blah
}
}
Creating an object is potentially arbitrarily complex. For POD types, it should be as cheap as an integer. For more complex types, it may at least involve a function call.
Everything is subject to the "as if" rule. The observable behaviour of the program is 'as if' int j was created, initialized and trivially destroyed 10 times.
Here, "initialize j" will be printed 10 times:
1 2 3 4 5 6 7 8 9 10
#include <iostream>
int main()
{
for( int i = ( (std::cout<<"initialize i\n"), 0 ) ; i < 10 ; ++i )
for( int j = ( (std::cout<<"\tinitialize j\n"), 0 ) ; j < 10 ; ++j )
{
// whateverh
}
}
Here, i, j and k will be optimized away:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
int foobar()
{
int k = 0 ;
for( int i = 0 ; i < 10 ; ++i )
for( int j = 0 ; j < 10 ; ++j )
++k ;
return k ;
//////// generated code /////////////
// __Z6foobarv:
// movl $100, %eax
// ret
//
// equivalent to: return 100 ;
//
//////////////////////////////////////
}