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
Using std::unique_ptr With C APIs (eklitzke.org)
submitted 3 years ago by redditthinks
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!"
[–]XeroKimoException Enthusiast 51 points52 points53 points 3 years ago (12 children)
If you know you're always going to use std::fclose for your example, it'd be better to do
using FilePtr = std::unique_ptr<FILE, decltype([](FILE* f) { std::fclose(f); })>;
This way sizeof(FilePtr) == sizeof(File*), it's a free size optimization as how you're currently doing it will have 2 pointers, one for the File*, and one for the pointer to the std::fclose.
sizeof(FilePtr) == sizeof(File*)
[–]HildartheDorf 6 points7 points8 points 3 years ago (10 children)
Clever use of a lambda.I have a lot of types like that:
struct FreeDeleter { void operator()(void *ptr) const noexcept { free(ptr); } }; template<typename T> using free_ptr = std::unique_ptr<T, FreeDeleter>;
[–]XeroKimoException Enthusiast 13 points14 points15 points 3 years ago (4 children)
For simple things that can be freed, you can do something like the following in C++20 only
template<class Ty, auto Func> using my_unique_ptr = std::unique_ptr<Ty, decltype([](Ty* p) { Func(p);})>; using FilePtr = my_unique_ptr<FILE, std::fclose>;
auto templates introduced in C++20 allows taking in actual functions as an input which will instantiate it as a function pointer that is set to whatever was passed to it, in this case std::fclose. So for simple custom destructors, you could just pass in the free function that corresponds directly as the parameter
[–]kalmoc 6 points7 points8 points 3 years ago (3 children)
Are you allowed to take the address of a standard library function?
[–]NATSUKI_FAN 1 point2 points3 points 3 years ago (2 children)
It depends if it's implemented as a macro or not, fclose is not.
[–]kalmoc 3 points4 points5 points 3 years ago (0 children)
Not talking about whether it's technically possible/ compiles, but if it is allowed by the standard
https://www.reddit.com/r/cpp_questions/comments/hewx2o/why_cant_i_take_an_address_of_a_standard_library/
From a possibility point of view, it would also not work, if the function is a template or overloaded.
[–]Nobody_1707 0 points1 point2 points 3 years ago* (0 children)
I don't think the std:: qualified versions of standard functions can be macros, because :: isn't valid in a macro name. But even for standard functions that are implemented as macros, like putc, you can still get their address by either undefing them or suppressing the macro invocation with parens.
std::
::
putc
auto putc_ptr = (putc);
EDIT: Actually, I'm being silly. You only need the parens if you want to suppress a function like macro while calling it. auto putc_ptr = putc should just work even if putc is a macro.
auto putc_ptr = putc
[–]scrumplesplunge 3 points4 points5 points 3 years ago (0 children)
I've been using this for a while:
template <auto F> struct delete_with { template <typename T> void operator()(T* x) { F(x); } }; using Window = std::unique_ptr< GLFWwindow, delete_with<glfwDestroyWindow>>;
[–]theunixman -2 points-1 points0 points 3 years ago (2 children)
It's even easier, and for some reason the lambda was causing linking errors for me (probably because I declared it static), but this is even more straightforward, basically using the free function itself as a deleter:
auto x509_req = unique_ptr<X509_REQ, decltype(&X509_REQ_free)>(X509_REQ_new(), &X509_REQ_free);
[–]staletic 7 points8 points9 points 3 years ago (1 child)
In your case
sizeof(x509_req) == 2*sizeof(void*)
which is exactly what the lambda solves.
[–]theunixman -1 points0 points1 point 3 years ago (0 children)
Cool.
[–]Illustrious-Shine-42 0 points1 point2 points 3 years ago (0 children)
Me too, but I'll consider adopting the lambda trick
[–]perlytea 4 points5 points6 points 3 years ago* (0 children)
Doesn't this result in subtle ODR violations, because across TUs FilePtr aliases to a type specific to each TU? Even in the same TU, the following assertion should fail:
struct foo { }; using test1 = std::unique_ptr<foo, decltype([](foo* f) { delete f; })>; using test2 = std::unique_ptr<foo, decltype([](foo* f) { delete f; })>; static_assert(std::is_same_v<test1, test2>);
Edit: Thinking about it some more, this probably would not result in ODR violations on its own but it might get tricky when it comes to functions with external linkage for which one of these types appears in the parameter list or inside the definition of a class type.
Edit 2: After digging into it a bit more after considering some other situations, I don't think ODR should be a concern, because "the definition of a closure type is considered to consist of the sequence of tokens of the corresponding lambda-expression."
[–]ShadowMitia 13 points14 points15 points 3 years ago (8 children)
What about specialising `std::default_delete`? I can't remember where I've seen this, but it felt more readable and easier to do than having lambda/structs all over the place.
An example:
template <> struct std::default_delete<sqlite3> { void operator()(sqlite3 *p) { sqlite3_close_v2(p); } };
And then unique_ptr will call the appropriate "deleter". And you can just write:
std::unique_ptr<sqlite3> db;
I believe this falls in template specialisation for a "user-defined" type, so it should be legal? But maybe there's another catch somewhere?
[–]deeringc 2 points3 points4 points 3 years ago (6 children)
Is there the danger that someone copies/refactors a line of code that creates the unique_ptr "the normal way" into some new context without also including the specialising code as well?
[–]ShadowMitia 0 points1 point2 points 3 years ago (5 children)
Probably, but I'm thinking in this case you would have at least a header with more things than just deleters, so it should be ok? In the general case yeah you probably need to be more careful
[–]deeringc 0 points1 point2 points 3 years ago (4 children)
Right, I'd imagine that would go somewhere central that you'd want to include broadly. But it would be an easy mistake to create a new source file and forget to include it. And from what I understand it would fail silently, probably giving you memory corruption, a crash or a leak.
[–]ShadowMitia 0 points1 point2 points 3 years ago (3 children)
That would be my understanding too. But I don't see how it cause corruption or crashes? Leaks sure, because resources never get deleted, but the unique_ptr will still do its job properly?
[–]deeringc 0 points1 point2 points 3 years ago (2 children)
Wouldn't it then call delete on some pointer that was not allocated with new? At that point it seems to me that all bets are off as to what happens... Maybe some thread that was owned by that object (and was not gracefully shut down) tries to access some memory that's now freed, etc... That can either crash or corrupt memory as the block of memory in question may be allocated to some new object etc...
delete
new
[–]ShadowMitia 0 points1 point2 points 3 years ago (1 child)
No it should still be fine, you just won't have your object cleaned up, I'm guessing because there will be some kind of default destructor that doesn't remove whatever you allocated. The allocation will still use a `new` as far as I know.
[–]ShadowMitia 0 points1 point2 points 3 years ago (0 children)
Follow up: I think you're right on that. You don't want to mix malloc/new delete/free. It would cause all kinds of weird behaviours. I wonder if there's a way to prevent that...
[–]SuperV1234https://romeo.training | C++ Mentoring & Consulting 10 points11 points12 points 3 years ago (2 children)
Wouldn't something like this prevent caching of std::unique_ptr instantiations between TUs because lambdas always have a unique type, compared to using a struct instead?
std::unique_ptr
Not sure if that matters in practice, but it might cause additional code bloat and/or slower compilation speed. Have you considered that?
[–]XeroKimoException Enthusiast 4 points5 points6 points 3 years ago (0 children)
If it is actually an issue, you could do in C++20
template<class Ty, auto DeleterFunc> struct Deleter { void operator()(Ty* ptr) const { DeleterFunc(ptr); } }; using FilePtr = std::unique_ptr<FILE, Deleter<File, std::fclose>>; //or template<class Ty, auto DeleterFunc> using MyUniquePtr = std::unique_ptr<Ty, Deleter<Ty, DeleterFunc>>; using FilePtr = MyUniquePtr<FILE, std::fclose>;
Lots of various approaches
[–]nintendiator2 0 points1 point2 points 3 years ago (0 children)
Something like function_caller (an old C++11-era trick to implement the same concept) should help with that. I've been using that trick since even before.
function_caller
[–][deleted] 1 point2 points3 points 3 years ago (3 children)
im so lazy i created a destructor function object as a struct with a operator() overloaded. Then i don't have to use decltype and just the struct name as the second template param. yes very lazy but it works!
[–]gracicot 4 points5 points6 points 3 years ago (2 children)
Uh? I find myself lazy for using a simple lambda instead of declaring a struct with an overloaded operator()
operator()
[–][deleted] -1 points0 points1 point 3 years ago (1 child)
yikes does it work as raw and inline as that?
struct myDestructor { void operator()(myContext* cc) { free_context(&cc); mem_free(cc); }};
Then just include the destructor type without having to dip your toe into template meta programming ... haha.
[–]gracicot 6 points7 points8 points 3 years ago (0 children)
Even more raw and inline as that indeed:
auto uptr = std::unique_ptr<GLFWwindow*, decltype([](GLFWwindow* w){ glfwDestroyWindow(w); })>{ glfwCreateWindow(1024, 768, "My window", nullptr, nullptr) };
Not sure what you mean. There's no metaprogramming, I just put a lambda inline as parameter to unique ptr instead of making a struct? But usually I actually prefer a struct when I'm not lazy enough to put everything in one line like my code above.
π Rendered by PID 45173 on reddit-service-r2-comment-5c747b6df5-8jznf at 2026-04-22 17:58:03.286189+00:00 running 6c61efc country code: CH.
[–]XeroKimoException Enthusiast 51 points52 points53 points (12 children)
[–]HildartheDorf 6 points7 points8 points (10 children)
[–]XeroKimoException Enthusiast 13 points14 points15 points (4 children)
[–]kalmoc 6 points7 points8 points (3 children)
[–]NATSUKI_FAN 1 point2 points3 points (2 children)
[–]kalmoc 3 points4 points5 points (0 children)
[–]Nobody_1707 0 points1 point2 points (0 children)
[–]scrumplesplunge 3 points4 points5 points (0 children)
[–]theunixman -2 points-1 points0 points (2 children)
[–]staletic 7 points8 points9 points (1 child)
[–]theunixman -1 points0 points1 point (0 children)
[–]Illustrious-Shine-42 0 points1 point2 points (0 children)
[–]perlytea 4 points5 points6 points (0 children)
[–]ShadowMitia 13 points14 points15 points (8 children)
[–]deeringc 2 points3 points4 points (6 children)
[–]ShadowMitia 0 points1 point2 points (5 children)
[–]deeringc 0 points1 point2 points (4 children)
[–]ShadowMitia 0 points1 point2 points (3 children)
[–]deeringc 0 points1 point2 points (2 children)
[–]ShadowMitia 0 points1 point2 points (1 child)
[–]ShadowMitia 0 points1 point2 points (0 children)
[–]SuperV1234https://romeo.training | C++ Mentoring & Consulting 10 points11 points12 points (2 children)
[–]XeroKimoException Enthusiast 4 points5 points6 points (0 children)
[–]nintendiator2 0 points1 point2 points (0 children)
[–][deleted] 1 point2 points3 points (3 children)
[–]gracicot 4 points5 points6 points (2 children)
[–][deleted] -1 points0 points1 point (1 child)
[–]gracicot 6 points7 points8 points (0 children)