To answer the questions:
- no restriction on
T
: if it works for standard containers it works for yours. - destruction is conditional, you can statically disable it if
std::is_trivially_destructible<T>
, else you must track constructed elements and only delete those which were actually constructed. - I don't see a major flaw in your idea, but make sure it is worth it: profile your use-case and check that you really spend a lot of time initializing elements.
I'm making the assumption that you implement your container as a block of contiguous memory of size size() * sizeof(T)
. Also, if the element's destructor must be called, i.e. !std::is_trivially_destructible<T>
, you must enable an additional storage, like a std::vector<bool>
of size()
elements use to flag elements for destruction.
Basically, if T
is trivially destructible, you just init when the user asks and don't bother with destroying anything. Else, things are a little more tricky and you need to track which element was constructed and which is uninitialized, so that you only destroy what's needed.
- up-sizing or container creation:
- if
!std::is_trivially_destructible<T>
resize flags storage accordingly - Memory allocation
- Optional initialization depending on what the user asked:
no_init
=> if!std::is_trivially_destructible<T>
, flag elements as non-initialized. Else do nothing.(Args...)
=> ifstd::is_constructible<T, class... Args>
call that constructor for each element. If!std::is_trivially_destructible<T>
, flag elements as constructed.
- if
- down-sizing or container destruction:
- Optional destruction:
- If
std::is_trivially_destructible<T>
do nothing - else for each element, if it is flagged as constructed, call its destructor
- If
- Memory deallocation
- If
!std::is_trivially_destructible<T>
resize flags storage accordingly
- Optional destruction:
From a performance point of view, if T
is trivially destructible, things are great. If it has a destructor, things are more constrasted: you gain some constructors/destructors calls, but you need to maintain additional flags storage - in the end it depends if your constructors/destructors are complex enough.
Also like some suggested in the comments, you could just use an associative array based on std::unordered_map
, add a size_t vector_size
field, implement resize
and override size
. That way, uninitialized elements would not even be stored. On the other hand, indexing would be slower.