The correct syntax for calling a destructor is
template<typename T>
void destruct(T& x)
{
x.~T(); // call destructor on x
}
// The below is valid even though ints do not have destructors
int x;
destruct(x);
That syntax is valid for types like int (when passed as a template parameter) but is a no-op (does nothing), so template code such as that in std::vector<T>
which calls destructors on its contents, is valid.
IMO it should be straightforward for the compiler to see that the loop contents contains a no-op, therefore the entire loop itself has no side effects, therefore remove the entire loop. Modern compilers have very sophisticated optimisers and should be more than capable of removing code which has no effect. If a compiler didn't remove redundant loops, it would emit redundant code in the destructor of a vector<int>
! There is no code to emit for the destructor of an int, so there would just be an empty loop iterating through the elements doing nothing. I'm sure any sane optimiser would remove that entire loop.
Of course, if you're calling the destructor on a class which does do work in its destructor, that must still be called and there will still be a loop (subject to other related optimisations such as unrolling).
Another simple example of optimisation based on side-effects is code like this:
for (int i = 0; i < 1000000; ++i)
; // just count up i, no statement (same as no-op)
cout << i;
will probably be optimised to simply print the constant 1000000 with no processing, because the compiler is smart enough to know the overall side effect is i
becomes a million and gets printed. This is the very basics for some of the impressive things optimisers do, so don't worry about it, it's going to do an excellent job. If you're ever curious, examine the output assembly in an optimised build to see what's really going on.