facing pimpls with no dynamic alloc
This week has truly blossomed into a time of severe macro abuse ^-^.
Problem case, we want to avoid declaring implementation details in a client-facing class, but we want the full size of that class up front so we don't have to allocate any memory at runtime.
This is not suitable for a library where the headers and implementation might diverge. In this case we're building a static library that links a second static library but don't want to expose details of that second library to our client application, and the client and libraries are always built together.
Usage is simple, we declare our type and expected size to create an 'impl' member:
Alongside the implementation we declare the known size and perform a compile-time assertion that everything is expected, that the client won't risk writing into memory they don't own.
#define M_Pimpl(num_bytes) \ struct Pimpl; \ uint8_t __pimpl_ptr[num_bytes]; \ Pimpl *impl = (Pimpl*)(&__pimpl_ptr); \ static constexpr size_t __pimpl_expected_bytes = num_bytes; #define M_AssertPimpl(name) \ static_assert(sizeof(name::Pimpl) > name::__pimpl_expected_bytes == false, \ "Unexpected sizeof " #name ", too small"); \ static_assert(sizeof(name::Pimpl) < name::__pimpl_expected_bytes == false, \ "Unexpected sizeof " #name ", too large");
We aren't able to directly get the size of our implementation in the assertion message because the sizeof operator is handled the compiler, after the preprocessor which would have ideally stringified it for us. But hey, it gives us enough detail to not go crazy over!
After a few minutes of usage,
M_FatPimpl has blessed us. The same functionality but with the 'too large' check ignored, allowing us to set a higher size during development (or if you're bored of a bullet-free foot, for shipping with an implementation size you can grow into)1.
It's worth noting you could hypothetically remove the assertion and change this into a dynamically allocated block later on - if you're okay with the torch-wielding mob marching when you unexpectedly raise the construction price.↩