Will unused destructor be optimized out?
Assuming MyClass
uses the default destructor (or no destructor), and this code:
MyClass *buffer = new MyClass[i];
// Construct N objects using placement new
for(size_t i = 0; i < N; i++){
buffer[i].~MyClass();
}
delete[] buffer;
Is there any optimizer that would be able to remove this loop?
Also, is there any way for my code to detec开发者_如何学编程t if MyClass
is using an empty/default constructor?
EDIT: Sorry about my horrible code. I think this is correct now..
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.
There are a few things wrong with this code.
Firstly, you don't need to be calling the destructor. MyClass buffer* = new MyClass[i]; delete[] buffer;
does that just fine. (Note, not the array syntax.)
That said, you comment leads me to believe you meant something else, like:
// vector, because raw memory allocation is bad
std::vector<char> memory(sizeof(MyClass) * count);
std::vector<MyClass*> objs; objs.reserve(count);
for (size_t i = 0; i < count; ++i)
objs.push_back(new (memory[sizeof(MyClass) * i]) MyClass()); // place it
Then later:
for (size_t i = 0; i < count; ++i)
objs[i].~MyClass(); // destruct (note syntax)
Of course there's no need to delete anything, since we used a vector. This is the correct syntax for calling a destructor.
Will it be optimized? It depends of the compiler can determine if the destructor does nothing. If the destructor is compiler-generated, I'm sure it'll remove the worthless loop. If the destructor is user-defined but in the header, it'll also be able to see it does nothing and remove the loop.
However, if it's in some other object file, I don't think it will, even if it's empty. That depends on your compilers ability to optimize during the linking phase. The best way to know is to look at the generated assembly.
You don't create a dynamic array as you have done above. You do it as follows:
MyClass* buffer = new MyClass[i];
That aside the loop you have above doesn't call the destructor either. If the class has an overloaded "~" operator then it will call that code.
So no ... no compiler will optimise that loop out. The code is highly unlikely to compile as well.
精彩评论