Hello and welcome to C++ Weekly.
I'm your host, Jason Turner.
I'm available for code reviews, contracting,
and on-site training.
And in the last episode, I covered how lambdas are
changing in C++ 20, and this is some of the many changes.
I specifically mentioned that we now have default constructable
lambdas, assignable stateless lambdas, and lambdas
in unevaluated contexts.
And I promised that, in the next episode,
I would show what that means.
So we left off with this code, and I'm going
to, for the moment, put the compiler back in C++ 17 mode.
And we are going to look at using a custom
deleter with unique pointer.
So I honestly cannot remember if I've done an episode that shows
this technique before.
I want to feel like I have, but I can't find an example of it.
So well, we'll just go ahead and recreate it here.
Let's say that we want some sort of file resource
that can be automatically cleaned up,
so we have some reason to use fopen and fclose.
You know unique pointer gives us a really handy way of managing
these things, so we can say this is a unique pointer
to object of type file.
And then we want a custom deleter
of some thing, something here.
We don't know what it's going to be.
I'm going to leave that blank.
And so, we're creating unique pointer,
and we're doing it with fopen something like this.
Now we have a few problems.
First of all, this code isn't compiling,
because we don't have our custom deleter set up yet.
And we probably also need to include some C header files,
but we're not getting any warnings on that.
So perhaps this is automatically being included with memory--
perhaps against the standard, but perhaps helpful
in this case.
So we want some way of cleaning up this file pointer,
and we know that we want to do that with fclose.
So we have our custom to deleter here.
And now we need to do something with it,
and we can do that with this decal type of the deleter,
and say that this is our thing.
But then we get another compile error here--
no matching function call to unique pointer, bla, bla,
bla, with this.
Candidate does this other thing.
And then, you know, this is C++, so the number of different
possible overloads in candidates we get is huge.
But this is the one we're looking for right here.
We need the deleter type owrite.
So let's rearrange this code a tiny bit.
I have the font a little bit bigger than usual,
so that this is all clearly legible.
So we've got something like this,
and what it's complaining about is that we're
missing the second parameter.
That's fine.
So we can pass in the deleter here, and that compiled.
So now what we have is this file object--
is this handy thing that's impossible to forget to close.
So we can use C file pointers if we need to for some reason.
Maybe we're working with operating system resources
or something like that.
And we can handily create this boilerplate automatic code
for us, so it doesn't matter how we were to exit main
or what were to happen.
The file would get closed correctly.
Now I'm going to put on optimizations here.
This is the kind of thing that we
do need to take advantage of optimizations for,
and we can see the code basically
just compiles to a call to fopen and a call to fclose.
It's straightforward, but this is weird.
Like, why do we have to do all of this--
define the thing up here, then do the decal type,
then copy it in?
This is where C++ 20 is going to come into play.
Now remember we said we have lambdas
in an unevaluated context, and we have default constructable
stateless lambdas.
So let's put this into 2a Mode.
So now that we have the compiler in a C++ 2a mode,
we can start to take advantage of these C++ 20 features.
So first of all, we can get rid of this,
because now that the lambda is default constructable
we don't have to pass one in, and the compiler has
no problem with this.
And now that we are allowed to use lambdas
in unevaluated context, we can take this, and put it here,
and get rid of this line.
And now we're able to say, I want something of this type.
It knows exactly what that is, but we have to give it a type.
We can't just give it an object in this case,
so we have to give it a type.
This is the lambda type right here,
and then it will default construct one.
We get all these helpful handy features of C++ with RAII,
an automatic management of lifetime of objects,
and everything works exactly we would like it to with safety
here.
And as you can see, at least with optimizations turned on,
it still just goes away to nothing.
So in the next episode, I'm going
to be revisiting an old topic, and try
to bring all this home for how this can help us--
and other cases, as well.
So thanks for watching and be sure to subscribe.