What are you actually trying to do?
What you're asking about has problems; they can be solved, but I'm just left asking myself, "why?" The thing you say you're trying to create sounds like a terrifyingly bad idea. Automagic initialization of vector elements is just asking for a serious pile of maintenance and performance problems.
It kinda maybe sounds like you maybe need a sparse array or maybe a stable vector or maybe are just looking for a free list, but I can't tell.
--
So far as your actual question, you'll have to keep track of which elements in your array are constructed or not. When you're about to free memory, walk the list of objects that are constructed and call their destructor. Then deallocate the memory. You should use the
C++ allocator model for allocations and deallocations and never call new, new[], delete, or delete[], unless you _really really_ have to (and you don't).
An option is to keep a parallel array of bits that you can iterate over and check to see which items are allocated. Something like:
template <typename T, typename A = std::allocator<T>>
class sparse_array
{
std::vector<std::aligned_union<0, T>::type, A> _data;
bit_vector<std::allocator_traits<A>::rebind_alloc<char>> _used;
public:
template <typename U>
void insert(siz_t index, U&& value)
{
if (index == _used.size())
{
_data.emplace_back();
_used.push_back(false);
}
assert(!_used[index]);
_used[index] = true;
_data.get_allocator().construct(&data[index], std::forward<U>(value));
}
template <typename U>
void push_back(U&& value)
{
auto index = _used.find_index(false);
insert(index, std::forward<U>(value));
}
T& operator[](size_t index)
{
assert(index < _used.size() && _used[index]);
return reinterpret_cast<T const&>(data[index]);
}
void clear()
{
for (size_t i = 0; i != _used.size(); ++i)
{
if (_used[i])
{
_data.get_allocator().destroy(reinterpret_cast<T*>(&_data[i]));
_used[i] = false;
}
}
}
~sparse_array() { clear(); }
sparse_array& operator=(sparse_array const& rhs); // check this!=&rhs, then clear(), then copy
sparse_array& operator=(sparse_array&& rhs); // check this!=&rhs, then clear(), then move
// ...
};
You'll need to find a bit_vector (there ones many online) or just use std::vector<bool> (shudder) - and of course learn how to rebind the allocator to it - but that's the gist.
You should also be sure to make the container fully conforming to the C++ container requirements (mostly by forwarding functions and type alises to the internal vector).
--
You also seem to have an important misunderstanding of how the C++ allocation operators work (the ones I just said you shouldn't use, and this is partly why):
ptr = new (sizeof(T) * 5);
new (ptr) T();
&ptr[0]->~T();
delete[] ptr; // Calls the destructor on invalid objects
Your error is that you're allocating with new but freeing with delete[]. You MUST pair new with delete and new[] with delete[], always. If you used C++ allocators, you'd use allocator_traits<Allocator>::allocate and ::deallocate to acquire and release memory, allocator_traits<Allocator>::construct and ::destroy to invoke the constructor and destructor when needed.
This model avoids the nastiness of new and delete, makes your code easier to audit for bugs, and allows users of your class to supply custom allocators which is a _very_ frequent requirement in games (many games mandate that the default allocator - including new/delete/malloc/free - can never ever be used; not just replaced with something else, but never used).
If all you're doing is storing an array and doing your own tracking of lifetime, just use std::vector over something like std::aligned_union<0, T>::type; then you can explicitly construct or destruct items in the vector but the memory is managed intelligently for you with full allocator support.