Live data from Hacker News

Implementing a class with void*

web.eecs.utk.edu

31–40 of 78 posts

Re: Implementing a class with void*

#32
post #12

Earlier quoted context omitted.

It is not an industry standard way. It is not a sensible way. It is not even a C way. As others have said, there's no reason whatsoever to use void* here. Just declare the struct without defining it in the header. Then only define it in the C file. C is fine with pointers to structs which are merely declared but not defined.

It is a de facto standard in that it is fairly widely documented and actually done. It's not in any ISO or IEEE standard or anything of the sort. There is almost no reason whatsoever to use void * anywhere other than to write a declaration that is compatible with another one which uses it. (A pointer to any object is better implemented as a typedef for unsigned char * . This requires a cast in both directions, thus i…

It (using a void pointer) is a worse way of doing PIMPL. Give the class a name, but don't expose its implementation (use an opaque class). This means that within the file or files that have access to the full implementation the correct type is present and no casts are needed.

Well, what if the actual class is a template? No matter, you can derive a class from a template, as in:

header: class Impl;

implementation:

class Impl: public std::vector { ... };

People who don't do this and use void* wind up with an implementation that has lots of casts in it, and it's easier to introduce bugs, especially once you get to the point where you have two or more hidden implementations.

Re: Implementing a class with void*

#33

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…

Might not make much of a difference with precomputed headers, but if you can't or don't use those, that should still provide quite a bit of speed-up. I went through the same exercises back when I did C++, but couldn't use PCH because some dependency did weird things and didn't exactly work anymore.

These days I wish there was something similarly easy to speed up Webpack builds ...

Re: Implementing a class with void*

#34

Earlier quoted context omitted.

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 can use a custom deleter, e.g. 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.

[deleted]

Re: Implementing a class with void*

#35

Earlier quoted context omitted.

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 can use a custom deleter, e.g. 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.

That breaks make_unique. Maybe unique_ptr inside an std::any? Error-prone casting, but managed lifetime. Though make_unique is maybe obsolete now that parameter evaluation order is better defined.

Re: Implementing a class with void*

#36
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.

The usual solution is to out Impl in a separate implementation header, so that implementation headers of derived classes can include it, but the rest of the world doesn't need to see it.

Re: Implementing a class with void*

#37
post #31

Yes, as others have said, using an opaque class is preferable to using a void pointer. class Impl; This isn't just for hiding, it also gives you faster compilation.

> This isn't just for hiding, it also gives you faster compilation.

That seems unlikely. What are you basing this on?

Re: Implementing a class with void*

#38
post #32

Earlier quoted context omitted.

It is a de facto standard in that it is fairly widely documented and actually done. It's not in any ISO or IEEE standard or anything of the sort. There is almost no reason whatsoever to use void * anywhere other than to write a declaration that is compatible with another one which uses it. (A pointer to any object is better implemented as a typedef for unsigned char * . This requires a cast in both directions, thus i…

It (using a void pointer) is a worse way of doing PIMPL. Give the class a name, but don't expose its implementation (use an opaque class). This means that within the file or files that have access to the full implementation the correct type is present and no casts are needed. Well, what if the actual class is a template? No matter, you can derive a class from a template, as in: header: class Impl; implementation: cla…

[deleted]

Re: Implementing a class with void*

#39
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…

> ...you can change your implementation and retain binary compatibility... 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.

> Maybe? I can still think of ways to have ABI problems in the implementation of class C.

Yes which is why GP is speaking in terms of allowance. Using this pattern you can retain ABI compatibility, that doesn’t mean you do and it’s otherwise a free for all.

Re: Implementing a class with void*

#40

Earlier quoted context omitted.

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.

The usual solution is to out Impl in a separate implementation header, so that implementation headers of derived classes can include it, but the rest of the world doesn't need to see it.

I mean, yes, but that's just the start of it. Suddenly you need to add contortions (like, say, 2-phase initialization) if you need to e.g. add virtual methods to Impl. You can keep adding workarounds after workarounds until everything works; my general point is just that supporting subclasses now becomes more painful, and you end up having to (in some sense) fight the language. It's nowhere near as free of a lunch as people make it out to be.
Post reply on HN