The C++ standard defines "undefined behaviour" as follows:
behavior for which this standard imposes no requirements
So if you want your code to be portable to different compilers and platforms, then your code should not depend on undefined behavior, because what the programs (that are produced by different compilers compiling your code) do in these cases may vary.
If you don't care about portability, then you should check if your compiler documents how it behaves under the circumstances of interest. If it doesn't document what it does (and it doesn't have to), beware that the compiler could change what it does without warning between different versions. Also note that its behaviour may be non-deterministic. So for example it could crash 1% of the time, which you may not notice in ad-hoc testing, but will come back and bite you later when it goes into production. So even if you are using one compiler, it may still be a bad idea to depend on undefined behavior.
With regard to your specific example, you can rewrite it to achieve the same effect (not calling destructor, but reclaiming memory) in a way that does not result in undefined behaviour. Allocate a std::aligned_storage
to hold the Foo array, call placement new to construct the Foo array on the aligned_storage
, then when you want to deallocate the array, deallocate the aligned_storage
without calling placement delete.
Of course this is still a terrible design, may cause memory leaks or other problems depending on what Foo::~Foo()
was supposed to do, but at least it isn't UB.