Live data from Hacker News

Implementing a class with void*

web.eecs.utk.edu

61–70 of 78 posts

Re: Implementing a class with void*

#61

Earlier quoted context omitted.

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…

Between this trick and generous use of forward declarations, I was able to remove almost all "headers included from headers" from a past project of mine, speeding up compilation by probably 3X (never measured it but it was observably faster). Maybe today's compilers optimize all these includes away and it doesn't make a difference anymore but it used to. These are the kinds of refactorings you often need to justify w…

I had 2x and I wasn't done... and this was a C with classes style project, so minimal templates and header complexity..

A much better alternative than precompiled headers.

Re: Implementing a class with void*

#62
post #55
post #4

I'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…

Yes, but doesn't std::unique_ptr introduce compiler / toolchain constraints? I.e. if the class declaration was in a header file of a library, as a user of the library you'd be bound to the same toolchain as the library, no?

Considering this is C++ rather than C and it doesn't have a portable ABI to begin with officially you'd have to use the same toolchain regardless.

In practice you get a strong amount of compatibility between Clang and GCC at the compiler level (since Clang basically copies GCC's ABI). But you also get the same fudging at the stdlib level with std::unique_ptr because it's header-only and is a zero overhead abstraction for a raw pointer (i.e. at the ABI level a normal unique_ptr is the same as a pointer except you can't move it around in a register).

Re: Implementing a class with void*

#63
post #56
post #42

Earlier quoted context omitted.

It means that the header that declares class A doesn't have to #include the header that declares class B, unless B is a part of its public interface. It doesn't sound like much, but the implementation dependency chain can be much longer in practice; and more importantly, all those savings apply to every translation unit that includes the header.

Ah, that's what you meant. Your previous comment reads as if an opaque class results in faster compilation than a void pointer, but those are the same as far as that goes, and you were comparing both to a non-pimpl version.

There might be a few hundred CPU cycles saved in compilation from not having to static cast the void* pointer to the implementation class.

Re: Implementing a class with void*

#64
post #56

Earlier quoted context omitted.

Ah, that's what you meant. Your previous comment reads as if an opaque class results in faster compilation than a void pointer, but those are the same as far as that goes, and you were comparing both to a non-pimpl version.

There might be a few hundred CPU cycles saved in compilation from not having to static cast the void* pointer to the implementation class.

Haha, sure, and the other way around, time is spent constructing the compile-time type info for the pimpl class. Let's ignore both since the impact would be so small it would almost certainly be drowned out by all the random noise that happens all the time.

Re: Implementing a class with void*

#65
post #4

I'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.

You have to do that anyway, unique_ptr only makes forgetting that a compile error.

Re: Implementing a class with void*

#66
post #55

Earlier quoted context omitted.

Yes, but doesn't std::unique_ptr introduce compiler / toolchain constraints? I.e. if the class declaration was in a header file of a library, as a user of the library you'd be bound to the same toolchain as the library, no?

Considering this is C++ rather than C and it doesn't have a portable ABI to begin with officially you'd have to use the same toolchain regardless. In practice you get a strong amount of compatibility between Clang and GCC at the compiler level (since Clang basically copies GCC's ABI). But you also get the same fudging at the stdlib level with std::unique_ptr because it's header-only and is a zero overhead abstraction…

Neither does C, most devs mix the OS ABI with the programming language used to implement the OS.

Re: Implementing a class with void*

#67
post #18

This 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…

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…

This is incorrect. I participated in the committee discussions around launder, byte, pointer provenance, and implicit object creation. None of those issues show up here. This is a very simple case of using placement new into a properly aligned char buffer to create an object at that location. This has worked just fine since C++98 and is not impacted by the many other object/lifetime/pointer issues that are being discussed.

Additionally, implementers are in completely agreement here that this works. There are zero standardization/implementation concerns with this method, and I would highly advise against scaring users away from it when necessary.

Re: Implementing a class with void*

#68
post #4

I'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…

It's kind of ironic that you declared it protected given that the poor subclasses won't actually have a definition to work with... which is incidentally one of the reasons not to do this.

> It's kind of ironic that you declared it protected given that the poor subclasses won't actually have a definition to work with... which is incidentally one of the reasons not to do this.

i see you haven't heard of the occult powers of going to peek into the source file, copying the impl struct definition in your own source and going for a big bad reinterpret_cast

Re: Implementing a class with void*

#69
post #4

I'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…

This also significantly hurts readability, and I would hate the person who writes code like this unless you really need binary compatibility (if you do, it is a sign that you should improve your release schedule). Mostly, you just want to decouple the interface of the class from the implementation details. In that case do just that - define an interface and implement it elsewhere. You can always just static link all…

> You can always just static link all binaries.

Not always you can't. There are many reasons to use dynamically linked libraries all of which are applicable whether you're using PIMPL or not.

Re: Implementing a class with void*

#70
post #56
post #42

Earlier quoted context omitted.

It means that the header that declares class A doesn't have to #include the header that declares class B, unless B is a part of its public interface. It doesn't sound like much, but the implementation dependency chain can be much longer in practice; and more importantly, all those savings apply to every translation unit that includes the header.

Ah, that's what you meant. Your previous comment reads as if an opaque class results in faster compilation than a void pointer, but those are the same as far as that goes, and you were comparing both to a non-pimpl version.

Yes, I was comparing

class Foo;

to

#include "Foo.h"

and I would not consider using a void pointer for anything other than an allocator.

Post reply on HN