Earlier quoted context omitted.
> and maybe more surprisingly, add/removing virtual functions I don't have the spec handy but fairly certain that v-table implementation is compiler specific and while it may work it isn't guaranteed. However if you declare the function symbols as dynamic then you can leverage the linker to dynamically resolve the right symbols with the matching opaque data and achieve binary compatibility(assuming you use the same c…
vtable layout is defined by the ABI, which is (mostly) consistent across major compilers everywhere except MSVC, however if MSVC ever broke vtable layout then everything that relies on COM would break on Windows. Which is basically all of Windows user space.
Implementing a class with void*
21–30 of 78 posts
Re: Implementing a class with void*
#22I'm surprised he doesn't refer to it by name (Pimpl). In C++ it has the advantage that you can change your implementation and retain binary compatibility because the size of your class doesn't change as you add/remove member variables (and maybe more surprisingly, add/removing virtual functions). If you're going to use C++, seems like it would be better to avoid the void* by class C { protected: struct Impl; std::uni…
The downside of unique_ptr used this way is that you have to define ~C in the same translation unit that the declaration of C::Impl lives.
Re: Implementing a class with void*
#23Re: Implementing a class with void*
#24Re: Implementing a class with void*
#25I'm surprised he doesn't refer to it by name (Pimpl). In C++ it has the advantage that you can change your implementation and retain binary compatibility because the size of your class doesn't change as you add/remove member variables (and maybe more surprisingly, add/removing virtual functions). If you're going to use C++, seems like it would be better to avoid the void* by class C { protected: struct Impl; std::uni…
The downside of unique_ptr used this way is that you have to define ~C in the same translation unit that the declaration of C::Impl lives.
struct deleter_t { void operator()(impl_t *); };
using impl_unique_ptr_t = std::unique_ptr;
You can place the implementation of the deleter alongside the impl.Re: Implementing a class with void*
#26Back in the 1990s, the video game company I worked at would hang a couple of extra void pointers in every class just to, you know, store extra things that are needed as time goes on…
This was common in the 90s, BeOS had these everywhere in its API classes
See `OSMetaClassDefineReservedUnused` in `OSObject.cpp`, here: https://github.com/apple/darwin-xnu/blob/main/libkern/c++/OS...
Re: Implementing a class with void*
#27This is a well-known way to achieve separation of definition and implementation. The disadvantage of the method proposed in the article is that, now everything needs a pointer indirection. A solution that fixes the drawback is used by lz4's library implementation: instead of storing a void star, store a char[] array of same size as the real struct. (of course, now you have to manually make sure the struct size are in…
Why not `typedef struct state state_t` in the header file, then have a `state_t state` in the header file with the `struct state { ... }` definition in the source file? This is similar to what I do in C, I don't see why it wouldn't work in C++.
Re: Implementing a class with void*
#28Earlier quoted context omitted.
Or don't do that (the char array trick) in C++ because implementers and standardizers are not clear about when/if you are allowed to store other objects in an array of chars, and even if you are it is tricky because you need to manually manage the alignment, or they are attempting to replace char with std::byte in the long term but don't really have a comprehensive and detailed plan to do so, etc. The implementation…
Yes, strict aliasing (or type-based alias analysis?) is quite crazy, and there are some murky dark corners where the specification is different between C and C++.. I think they have a std::launder thing exactly for this purpose of "safely casting an array of bytes into an object". However, in this particular case (of using char array to hide real implementation), the implementation resides in another translation unit…
But then I force myself to find a second reason for why the program will run correctly, and unfortunately nowadays it is more and more being strictly-conforming. Relearning std::launder, TBAA, pointer provenance, etc. every time is way too consuming. I'm forced to give-up on programmer optimization and hope for the compiler to be really up to its mythical promises (and this yet: without LTO; too dangerous...)
Re: Implementing a class with void*
#29I'm surprised he doesn't refer to it by name (Pimpl). In C++ it has the advantage that you can change your implementation and retain binary compatibility because the size of your class doesn't change as you add/remove member variables (and maybe more surprisingly, add/removing virtual functions). If you're going to use C++, seems like it would be better to avoid the void* by class C { protected: struct Impl; std::uni…
Came here to say exactly that. You can also do this, thought it looks a little worse it allows for even more flexibility, such as complete decoupling of Impl from A across different files: // Forward declaration of Impl. What does Impl do? // You're not allowed to know. class Impl; class A { protected: Impl* mImpl; }; I've been using this trick but for a different reason - to reduce the number of #include statements…
These are the kinds of refactorings you often need to justify with hours of arguments and approvals and religious fights and code reviews at work, but can do in an afternoon in a private project just because it makes the code nicer.
Re: Implementing a class with void*
#30I'm surprised he doesn't refer to it by name (Pimpl). In C++ it has the advantage that you can change your implementation and retain binary compatibility because the size of your class doesn't change as you add/remove member variables (and maybe more surprisingly, add/removing virtual functions). If you're going to use C++, seems like it would be better to avoid the void* by class C { protected: struct Impl; std::uni…
Maybe? I can still think of ways to have ABI problems in the implementation of class C.
It's true that there are fewer ABI problems to worry about, though.