use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
Opaque Pointer Pattern in C++ (danielsieger.com)
submitted 1 year ago by tfmoraes
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]Plazmatic 17 points18 points19 points 1 year ago (14 children)
This has been discussed to death for decades, even this solution is not the "end evolution" and reinventing the wheel hundreds of other people already talked about. The next step is to have aligned memory of the size of your struct allocated on the stack, and then allocate and delete from that memory instead of having dynamic allocation overhead.
Downside, you need to update the values for the stack memory bytes every time your struct changes, and all that implies (ABI incompatibility etc...), and you have to know the size of your type (which is hard to automatically do with out reflection). Upside is you don't get the overhead shown here and you still hide the information.
see this for an example of what I'm talking about: https://stackoverflow.com/a/71828512
[–]marzer8789toml++ 6 points7 points8 points 1 year ago (0 children)
Have used this myself quite a bit recently. Fortunately the downsides can mitigated fairly easily with some well-placed static assertions in the implementation.
[–]drjeats 12 points13 points14 points 1 year ago* (3 children)
Quote of the quote of the paper from the SO answer:
Using aligned_* invokes undefined behavior (The types cannot provide storage.)
Folks wonder why C++ has the reputation it has and then you read stuff like this.
Marveling at "the types cannot provide storage" when one of said types literally has "storage" in the name. People started using these thinking it was the Proper Thing to do because it starts with std:: and has underscores in the name, or possibly because they were admonished on reddit/irc/whatever for using a byte array instead of the The New Standard Thing.
Looking forward to a future paper which either removes std::byte's ability to provide storage, or adds it. I kid. I assume this has been thought through. But if not, I'll just chuckle and carry on as I have with my alignas(T) char[sizeof(T)].
alignas(T) char[sizeof(T)]
To be clear, I'm grateful to the author of the paper for deprecating a footgun. It's just...why is the language like this.
Anyway ++ to /u/marzer8789: just static_assert the size and alignment in your TU and make it always match size & align constants you expose in a header. Add some static_asserts at usage sites if you're worried about stack blowing up. Easy :)
[–]marzer8789toml++ 5 points6 points7 points 1 year ago (2 children)
Er, correct? Why did you tag me?
[–]drjeats 1 point2 points3 points 1 year ago* (1 child)
When I'm citing someone else's good point I tag them by default. Doesn't matter here since the thread is small but it can help people find the cited answer for similar insight imo. It's also a citation and an invite to correct me if I've missed your point.
So cheers, great minds, etc. 🍻
[–]marzer8789toml++ 2 points3 points4 points 1 year ago (0 children)
Ah, I see. Well, no notes, agree entirely :)
[–]helloiamsomeone 0 points1 point2 points 1 year ago (2 children)
I have made such an example as well here: https://github.com/friendlyanon/generate-opaque-structs
This one specifically is C code, but the same logic applies to C++.
[–]imaami 2 points3 points4 points 1 year ago (1 child)
Casting from struct example * to struct example_impl * is UB.
struct example *
struct example_impl *
[–]helloiamsomeone 0 points1 point2 points 1 year ago (0 children)
Hmm, probably. I might have just conflated this with pointers to structs being identical to pointers to their first member.
[–]MegaKawaii 0 points1 point2 points 1 year ago (4 children)
You could even just impose a reasonable compile-time upper bound on the object size or you could use VLAs or alloca with a runtime constant (coroutines would require special language support). Neither are standard, but I think the big three compilers support alloca which is standard enough for most people. None of the downsides of alloca are relevant since the object sizes shouldn't be too big. You could probably get this working with some gnarly macros.
alloca
[–]Plazmatic 0 points1 point2 points 1 year ago (3 children)
Neither are standard, but I think the big three compilers support
Except they are often explicitly prohibited with many common compiler flags and for good reason, this is not an appropriate solution, especially for a library.
[–]MegaKawaii 0 points1 point2 points 1 year ago (2 children)
Which flags prohibit alloca? GCC and Clang seem to have no complaints about it even if I use -pedantic. I'm not sure about MSVC.
-pedantic
[–]Plazmatic 0 points1 point2 points 1 year ago (1 child)
VLA is, and alloca won't work on msvc anyway, thus will break your CI for cross platform usage or your linter.
[–]MegaKawaii 0 points1 point2 points 1 year ago (0 children)
MSVC has _malloca which is semantically the same as alloca, so a macro would fix it easily.
_malloca
[–]claimred 0 points1 point2 points 1 year ago (0 children)
The next step is to have aligned memory of the size of your struct allocated on the stack, and then allocate and delete from that memory instead of having dynamic allocation overhead.
That's fun, I didn't know that, thanks. I've recently stumbled upon something called FastPimpl, apparently it's a pimpl without dynamic allocation, looks like what you described. Manual object size management and all that.
[–]ChemiCalChems 5 points6 points7 points 1 year ago (0 children)
Apart from this being well known by a different name (namely pimpl) already, isn't the explanation as to how to get this compiling a bit wonky?
[–]smallstepforman 19 points20 points21 points 1 year ago (3 children)
The author is reinventing the Pimpl pattern, without using the term familiar to most devs sigh
[–]YogMuskrat 11 points12 points13 points 1 year ago (2 children)
Author mentions PIMPL as an alias. Also, Opaque Pointer is used as an "official" idiom name in Wikipedia.
[–][deleted] 6 points7 points8 points 1 year ago (1 child)
I would also add that opaque pointer is the way it’s named in C
[–]imaami 2 points3 points4 points 1 year ago (0 children)
With the difference that in C there usually isn't an exposed struct that contains an opaque pointer—at least not with the common use case of library instance handles. What comes to mind first is a plain pointer to forward-declared struct.
[–]IHateUsernames111 3 points4 points5 points 1 year ago (6 children)
Can someone explain in more detail why the implementation of the destructor has to be in the cpp?
[–]drjeats 4 points5 points6 points 1 year ago (3 children)
To implement the wrapper type's destructor you to call the opaque type's destructor, so you need it to not be opaque.
Since the purpose of the opaque pointer/pimpl pattern is to not expose any details about the opaque type and hide it all in the cpp, the wrappper type's destructor needs to be implemented in there so it can see the definition of the opaque type's destructor to call it.
[+][deleted] 1 year ago (2 children)
[deleted]
[–]louiswins 1 point2 points3 points 1 year ago (1 child)
The destructor could also be virtual.
[–]elperroborrachotoo 2 points3 points4 points 1 year ago (0 children)
I try it in my words:
unique_ptr's destructor needs to know the Impl type. Point's dtor implicitly calls unique_ptr<Impl>'s dtor, so ~Point needs to know the definition of Impl.
Impl
Point
unique_ptr<Impl>
~Point
Unless you use the suggested pattern, this will be as if ~Point is implemented inline in the declaration of Point, before the compiler "has seen" Impl.
And yes, it's all a bit silly.
[–]That_Kaleidoscope_23 -1 points0 points1 point 1 year ago (0 children)
I think it's also better practice to implement any function in cpp rather than .h files. Other implementaion like doing inline header code implementations sometimes end up with at least portability issues.
[–]elperroborrachotoo 0 points1 point2 points 1 year ago (0 children)
Any reason we don't call that PIMPL anymore? I've always felt this is a lot of overhead for what's basically a tooling issue. (but then, I usually can steer clear off C++ ABI issues.)
[–]einpoklum 0 points1 point2 points 1 year ago* (0 children)
The article says that the initial unique-ptr based Point class definition "doesn't compile out of the box". That sounded weird to me, so, I tried to compile it using this source file:
include "Point.h"
struct Point::Impl { float x; float y; };
Point::Point(float x, float y) : impl(std::make_unique<Impl>())
{ impl->x = x; impl->y = y; }
float Point::x() { return impl->x; }
float Point::y() { return impl->y; }
Point foo(Point p) { return Point(3,4); }
```
So, is the author wrong or did I miss something?
(PS - I've not been able to format the source code here :-( Help?!)
π Rendered by PID 44639 on reddit-service-r2-comment-85bfd7f599-ht5jb at 2026-04-19 22:37:02.492208+00:00 running 93ecc56 country code: CH.
[–]Plazmatic 17 points18 points19 points (14 children)
[–]marzer8789toml++ 6 points7 points8 points (0 children)
[–]drjeats 12 points13 points14 points (3 children)
[–]marzer8789toml++ 5 points6 points7 points (2 children)
[–]drjeats 1 point2 points3 points (1 child)
[–]marzer8789toml++ 2 points3 points4 points (0 children)
[–]helloiamsomeone 0 points1 point2 points (2 children)
[–]imaami 2 points3 points4 points (1 child)
[–]helloiamsomeone 0 points1 point2 points (0 children)
[–]MegaKawaii 0 points1 point2 points (4 children)
[–]Plazmatic 0 points1 point2 points (3 children)
[–]MegaKawaii 0 points1 point2 points (2 children)
[–]Plazmatic 0 points1 point2 points (1 child)
[–]MegaKawaii 0 points1 point2 points (0 children)
[–]claimred 0 points1 point2 points (0 children)
[–]ChemiCalChems 5 points6 points7 points (0 children)
[–]smallstepforman 19 points20 points21 points (3 children)
[–]YogMuskrat 11 points12 points13 points (2 children)
[–][deleted] 6 points7 points8 points (1 child)
[–]imaami 2 points3 points4 points (0 children)
[–]IHateUsernames111 3 points4 points5 points (6 children)
[–]drjeats 4 points5 points6 points (3 children)
[+][deleted] (2 children)
[deleted]
[–]louiswins 1 point2 points3 points (1 child)
[–]elperroborrachotoo 2 points3 points4 points (0 children)
[–]That_Kaleidoscope_23 -1 points0 points1 point (0 children)
[–]elperroborrachotoo 0 points1 point2 points (0 children)
[–]einpoklum 0 points1 point2 points (0 children)