However, according to the IRC channel, a call to the constructor / destructor can be optimized if the compiler does not see a side effect for SomeClass constructors / destructors.
The bold part is incorrect . It should be: knows there is a lack of observable behavior
eg. from Β§ 1.9 of the last standard (there are more relevant quotes):
The corresponding implementation, executing a well-formed program, should provide the same observable behavior as one of the possible executions of the corresponding instance of an abstract machine with the same program and the same input. However, if any such execution contains an undefined operation, this International Standard Seats does not require the execution of this program with this input (not even for operations preceding the first undefined operation).
In fact, this whole mechanism underlies the synergy of the most ubiquitous C ++ idiom: Resource Initialization
Backgrounder
To optimize the compiler, trivial case constructors are extremely useful. This is what allows iterators to compile to the exact same performance code, using raw pointers / indexers.
It also allows the function object to compile the same code as the embedding of the function body.
This is what makes C ++ 11 lambdas completely optimal for simple use cases:
factorial = std::accumulate(begin, end, [] (int a,int b) { return a*b; });
A lambda compiles to a functor object similar to
struct lambda_1 { int operator()(int a, int b) const { return a*b; } };
The compiler sees that the constructor / destructor can be discarded and the body of the function will turn out to be nested. The end result is optimal 1
More (un) observed behavior
The standard contains a very interesting example, on the contrary, to spark your imagination.
Β§ 20.7.2.2.3
[ Note:
Usage count updates caused by the creation and destruction of a temporary object are not observable side effects, so an implementation can satisfy effects (and implied warranties) through a variety of ways, without creating a temporary one. In particular, in the example:
shared_ptr<int> p(new int); shared_ptr<void> q(p); p = p; q = p;
both appointments can be non-op. βend note ]
IOW: Don't underestimate the power of compiler optimization. This in no way means that language guarantees should be thrown out of the window!
1 Although there may be faster algorithms for obtaining factorial, depending on the problem area :)