Live data from Hacker News

Implementing a class with void*

web.eecs.utk.edu

51–60 of 78 posts

Re: Implementing a class with void*

#51
post #41

Earlier quoted context omitted.

You don't need to cast anything - just placement-new it inside the array. So long as the array is properly aligned, this is fine. After that, it would be UB to peek at the bytes of the object via the array because of aliasing issues, but I don't see why it would be improper to use the pointer returned by new.

After the object is constructed by placement-new, the class methods still needs to reinterpret_cast the char array to an object pointer to access the object. I don't think in this specific case there is an UB involved, but I'm not language standard lawyer so I'm not sure. I feel the standard's specification on what is allowed to reinterpret_cast and what isn't is arcane (or at least far from straightforward to unders…

Not too terrible to create a private method that does the reinterpret_cast for you.

I've had to use this technique in the past and therefore dived into the standard for quite a while. I don't recall encountering any UB concerns.

Re: Implementing a class with void*

#52
It seems kind of stupid to use "-std=c++98" when building this stuff. Nothing in later Standards interferes with it.

Maybe it is meant to serve notice that the method is archaic, and that better ways to achieve the same thing will be presented later. But then one might just as well code the throwaway examples in C and use a damn C compiler. It's archaic even for C. There is just no merit in storing a void* that will then be cast to some arbitrary other known type every time it is used.

The only really valid use for a void pointer is when it is being passed through a subsystem and comes back to somebody who knows what it is, such as when an abstract handler function is being registered along with a pointer to some context that will be passed to the handler; this is extremely common in C code.

In C++, you can just take a pointer to a type T with virtual member f() you promise to call. The caller supplies a pointer to T2 derived from T and with its own f(). This, too, feels a bit archaic, but is at least not actively silly.

Re: Implementing a class with void*

#53

Earlier quoted context omitted.

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…

I don't see why you need 2-phase for virtual functions. But yes, I don't think anybody claims is a free lunch. It is annoying, verbose, repetitive, but often necessary to keep the cose base complexity under check.

> I don't see why you need 2-phase for virtual functions.

I might be misremembering the "for virtual functions" part, but the inability of C to call Impl's constructor directly in the presence of a derived class can sometimes force you to delay some of the initialization until after Impl is constructed. ("Necessary" might be too strong here, in that you could find some other workaround too.)

> often necessary to keep the cose base complexity under check.

Hmm... I'm not sure I agree. A pimpl-like idiom can be necessary for solving a few very specific problems, which are explained in [1] better than I can here: (a) ABI stability, (b) slow compilation, and (c) exception safety. There are other niche cases I can think of (e.g. "I need fast/atomic swapping like a reference type, but copying like a value type"), and even those might have better solutions, but none of them really has anything to do with code complexity... they're either domain requirements you either have or don't have, like in (a)/(c)/(d), or they're workarounds for slow toolchains, as in (b). But unless you have requirements/constraints like these, I have a hard time recalling any common situations where pimpl would be the best solution, especially if it's for taming complexity.

[1] https://softwareengineering.stackexchange.com/a/213264

Re: Implementing a class with void*

#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?

Re: Implementing a class with void*

#56
post #42
post #37

Earlier quoted context omitted.

> This isn't just for hiding, it also gives you faster compilation. That seems unlikely. What are you basing this on?

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.

Re: Implementing a class with void*

#57

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…

Used to teach C++ - doing it this way is absolutely _not_ how to do or use the PIMPL idiom [0]. Declaring a private and opaque forward decl is very different to VOID* all the things. [0] https://en.cppreference.com/w/cpp/language/pimpl

The term ”PIMPL” itself (by far) predates all the cruft shown there.

Re: Implementing a class with void*

#58

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…

That breaks the ABI-compatibility part of this trick.

Re: Implementing a class with void*

#59

Earlier quoted context omitted.

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

You're reading a different inflection into "can" than I did, but it sounds like we agree that pimpl isn't sufficient for ABI stability.

Re: Implementing a class with void*

#60
post #54

Consider the rule of zero.

Interesting thing indeed. Would you care to expand?

Edit: This is interesting from the case of "beginning of the calendar" - coincidentally just read this from a reddit thread (linked):

> Let me start with a quote you may hear in a lot of history classrooms: "Jesus Christ has been born 7 years Before Christ", sounds a bit weird doesn't it. Yep, historically the idea was to mark his birth as a dividing point, however, there are a bit of problem of determining precisely what year we're trying to set as first one. To keep the meaning intact, we would have to move dates if we find better information about exact year of his birth, not convenient at all.

> When we say that we are in year 2012 CE, then we don't care that year 1 CE should be some specific event (there isn't year 0 in common notation BTW), we just need all agree on the same starting point. We leave the date intact because it's widespread, so it's more convenient not to change the date, the same way we still use non-decimal hours, minutes, seconds. If f.e. Anno Mundi (from Creation of the World) system remained in use in Europe with the agreement on the same date (Latin and Greek scholars disagreed on Biblical age of Earth), we would use it as Common Era.

https://www.reddit.com/r/TrueAtheism/comments/14nuuw/i_think...

This is interesting to me from a wild out there idea that feels similar to 'coordinate space for storing data.' Time as a coordinate space for simulations in a way.

Post reply on HN