Suppose I have some incomplete type
// in foo.hh
struct Hidden;
that I want to use as element type of a std::vector
. Using an union
I can "defer" calls to the constructor(s) and the destructor of the std::vector
to the implementation of the unions constructor(s) / destructor.
// in foo.hh
struct Public {
union Defer {
std::vector<Hidden> v;
Defer();
// add copy/move constructor if needed
~Defer();
} d;
};
Now I can use Public
by only including foo.hh
and linking with the file(s) implementing Public::Defer::Defer()
and Public::Defer::~Defer()
. Only those will need access to the full definition of Hidden
.
Is this legal C++? If so, since when?
Background: Question that came up in my answer to another question.
Instantiating std::vector<T>
with incomplete type T
is undefined behavior up to C++14. In C++17 this limitation is relaxed somewhat:
[vector.overview]/3 An incomplete type
T
may be used when instantiatingvector
if the allocator satisfies the allocator completeness requirements 17.6.3.5.1.T
shall be complete before any member of the resulting specialization ofvector
is referenced.
(Note: the default allocator std::allocator
does satisfy those completeness requirements).
My reading is that with C++17, it's legal for a translation unit to include your header (the one that forward-declares Hidden
and defines Public
), and define a variable Public pub;
- but not to actually use any members of pub.d.v
. Before C++17, merely including the header would already trigger undefined behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With