- Good afternoon.
I hope you all enjoyed the break.
I'm Peter Sommerlad.
Professor in Switzerland,
and designer of these hats.
I know some of the audience have a hat,
and I have six spare hats that
we will give out tonight tool time session
at 8 or 8:30 somewhere in this building.
So, let's take that off.
Scope Guards and Unique Resource.
Five plus years in the making.
I think this is one of the features
that should be in the standard library
that everyone would like to have,
but it's very hard to actually make.
And getting past the US
and the Senates committee.
And this is a story about that.
I will have some code that
is simple and easy to follow,
and some code that is just
too much to get on the side,
so don't expect to understand
everything that's on the slide.
I might not either.
What is a resource?
Some of you might know, but not everybody,
that I have a history before C++.
I'm an author of pattern books,
not of this one specifically,
but of the styling of that series.
And patterns are about
successful engineering.
So a lot of things that you hear
at conferences like this are
stories about successful,
or maybe not successful engineering.
And patterns are stories
about successful engineering.
Who owns a pattern book?
I always like to remember.
Who owns more than one pattern book?
Okay, there are plenty.
Not all of the pattern books
have pattern in the title,
but there's one on resource management,
and what you can see here is a kind of
the map of the patterns of that book.
I don't want to go into that detail,
but the biggest thing
you need to understand
is a resource is something
with the lifetime.
Usually, you need to acquire the resource.
Then you use it, and you release it again
back to what this book calls
the resource coordinator,
or resource manager.
Some resources are given to you
by the operating system
like a file handle,
or by the runtime system like memory.
Or, you might have resources
that you manage yourself,
and you have things like manager objects.
And there's a resource
manager in that book,
and I also wrote a pattern
on managing objects.
Resources can be exclusive or shared.
And the shared part is interesting.
Especially a thing like memory.
In fact many people, many frets,
or objects in the programming sharing
a whole global heap space
that can be contentious,
and you end up having problems.
If you run, if you don't manage
the life cycle correctly.
And usually not releasing
a resource can be an error.
Now who has programmed Java or
C# seriously in his/her life?
Especially the students that I deal with
that start out with Java,
they don't get the, let's say, the feeling
that they manage resources.
When they write new
it's just they have to.
They don't understand
that they grab memory
from a global heap that
somehow by magic is released
when they forget about the
objects if they do it correctly.
But even in Java, you
can't have memory release.
And these resource management consciously,
a C++ programmer or
especially a C programmer,
is much aware about resources.
Especially a C programmer has to actually
take great care not to leave memories
because everything is explicit.
And sometimes the APIs, even
in the C standard library
are inconsistent to those memory.
And that's just one of the many
resources we have to deal with
in real world programming.
So resource management is not easy,
you can write whole books on that.
Even the famous Gang of
Four Design Patterns,
now again, who knows about
that design pattern book?
Okay.
At least know about it.
It has a pattern called Factory Method,
and even a thing more infrastructural
like abstract factory,
but it forgets about disposal.
So if you acquire
something from a factory,
if that's the resource
that you need to manage,
you need a means to return it somewhere
so it can be reused or released.
And that's what Kevin Henney
wrote down, about in 2004.
And again the Gang of
Four Design Patterns book
there were some C++ programmer but also
Smalltalk programmers writing that.
And they forgot about mentioning that
because in Smalltalk S Java
has garbage collection.
Memory is not a resource
that you consciously
acquire and release.
You only recognize it's a resource
when you build up object cycles
that never get released
by the garbage collector.
And again it is to manage
the design patterns
at one of the less famous pattern books,
the Pattern Language of Programming.
The number three has my pattern in there,
and the manager design pattern
encapsulates management
of instances of a class,
so read that off resources,
into separate manager object
allowing variation of the
management functionality
independent of the class and
for the reuse of the manager
for different object classes.
That's a long thing to
say is the manager has
a factory and a disposal method.
You acquire resource by the factory
and return it by the disposal method.
So we always have these pairs
of using stuff in between,
keeping track of the resources.
Now C++ thankfully
has a very interesting facility
that is the curly closing brace.
That's the most important
syntactical element
we need to be aware of
because that allows us
to have a deterministic
object lifetime model.
We know when things pass out over in here,
retired or returned or destructed.
That's the current terminology.
So we have this cleanup.
Let's say the C++ global
generator curly brace, closing,
and destructors that
automatically run there.
And that's one of the cornerstones
that makes C++ so efficient
and effective for a lot of things,
especially for resource management.
And Bjarne Stroustrup coined the term
resource acquisition is initialization,
and it should go further on,
and running the destructor
is resource release.
So in the initialization,
in the constructor of an
object, you acquire the resource
and in the destructor you clean it up.
If you do it that way you never can forget
to dispose the resource as long
as you don't leak your object's lifetime
somewhere else and it stays there forever
in like global memory.
So scopes, closing curly braces,
allow us to do
resource management
sanely and safely in C++
even when you get exceptions
or unexpected control flow.
The cleanup runs always
if they're right.
C++ 11 made it even more useful
before C++ 11 the only clear,
good cleanup was scope based.
So you're in a scope,
you acquire resource,
and when you leave the
scope it's released.
And that's what worked.
There was a facility called auto pointer.
Someone still remembering that?
You're lucky if you don't
have to remember that
because it tried to
solve a problem without
having the language
facility to do it correctly,
and that was very interesting box,
and it was not recommended
to actually use.
Some people recommend it
and then others kept problems from that.
But C++ 11 we get move semantics,
and that allows us to actually
not only have the scope
as the environment of a resource
but having the uniqueness of the ownership
of the resource allowing us to
return a resource from a function
and having it clean up just once.
Just a single authority
owner of a resource.
For memory we have for that unique pointer
which is a replacement for auto pointer.
And for other things, well,
we have more.
But now why am I talking about this thing?
There is a generic RAII proposal.
In just a simple timeline of its life.
In the blue bars is the number of classes
in the proposal paper.
The red one is the number
of factory functions.
The greens, the optional
factory functions.
And if you look at that
it goes up and down.
And many, many releases.
So we are planning to
get release number nine
by October for the November
meeting in San Diego.
It's not written yet.
And it started out even
before we leave number zero.
So we have nine existing
releases with the P52
plus four previous paper making it 13.
And I'm not sure if we manage
to not get to release A.
I think that might be the first paper
that actually gets a
hexadecimal revision number.
Chances are high it gets rare.
But I've already proposed for the talk.
I was much more optimistic.
But optimism is,
one of the reasons why I still
have that paper in flight.
More on that later.
But there are more than just unique
resource that I propose in that paper.
There RAII classes in the standard
that help us to keep our head sane.
One could say anywhere where
destruction has a side effect
where the destructor is not
defaulted and not trivial,
but sometimes it's used to cheat.
But what we can definitely say
we have three file streams for example.
There the constructor will open the file,
if you don't do any
special things about it,
and the destructor will close the file,
release the resource, the open file
handle to the operating system.
That's a typical RAII
magic happening there.
We have unique pointer I talked about,
but also string, standard string.
It's a RAII.
Usually you acquire
memory that you allocate
when you create a string object
unless it's empty string.
You might extend that allocated memory
by extending the string.
But whenever you destroy a string object
the memory gets released.
So it's clean up automatically.
The same is true for all of
the containers that we have.
We have C++ 11,
and later on we have Mutaxs.
And Mutax is a typical
resource where you acquire it.
You use it then you release it.
And if you forget to release it
you get big problems like deadlocks or,
usually deadlocks.
And if you forget to acquire it
you get even more problems
like risk data erases,
which means unicorns, rainbows,
or whatever.
So any more from a viewer
hat, oops not again,
RAII classes.
Thread resource.
It is a resource.
Is the standard thread
class an RAII class?
Since I live in Switzerland
where voting is almost
every other weekend,
a quick show of hands.
Who thinks, just from
the top of your head,
no thinking, just feeling.
Who thinks standard
thread is an RAII class?
Who thinks not?
So what's the magic in thread?
If you don't join the thread,
running the destructor gives
you interesting effects.
(unmiced talking)
It's still initializing the constructor
but it's not really,
that's what's missing in the RAII.
The cleanup is not in
the destructor strength.
You have to do that explicitly which gives
a whole bunch of problems and (mumbles)
my talk hours on that with you.
We might get a scope thread for that.
Yes?
(unmiced talking)
There are proposals on making thread.
The question is isn't there
a joinable thread proposal
or something that is
actually an RAII thread?
There is.
It's not the standard
yet but we might get it.
Maybe it was voted in and
(mumbles) and I didn't get that.
But it's not NC plus
with 17, definitely not.
There's a little spoiler for tomorrow.
Using RAII classes makes your
code usually sane and safe,
meaning that things just
work well if you use RAII.
And that's the topic of tomorrow's talk.
Now writing interesting
destructors with side effect
is something that I try to
get my students not to do.
But nevertheless I have to show them
that there is something
else, like a destructor,
and the best thing is write crappy code
and show them how to use that.
And actually the person
guilty of that code
example is sitting in that room right now,
or is that from me?
I'm not sure.
Maybe.
So a tracer class, a perfect thing to see
that destructors with side effect,
to actually see when destructors run.
And that's the purpose of that code.
And whenever I use a pinkish background,
that's because that's code
you shouldn't write at home.
In my life I worked with complicated
OO frameworks in C++ as well.
Classes like that were
essential to understand
how the framework work
especially when you fucked up your code.
So you need it, sorry for my language.
You need a tracing printif debugging
because in multi-threaded code
running it in debugger it's very hard
to figure out what's wrong.
And I would say intact if debugging
is the worse thing a
professional programmer can do.
It's the biggest time waste.
The only means, and
there I am with (mumbles)
to run a debugger is
have a post-mortem dump
to analyze where the strike can,
where you get a deadlock or whatever,
crash, in your program.
Side note.
But again we are all professionals
so we know if there are rules
given by despotic trainer
like me or teacher like me.
There are always exceptions to the rules.
There is one exception to the rule
or one thing where, okay,
Java developers and others like in C#
tend to want to have destructors that run
at curly brace, and they didn't have that.
So they invented something like finally.
Now we have many programmers today,
programmers in C++ who
grew up with Java or C#,
and they would love to have finally.
We even have it in the C++ core
guidelines support library.
There are several other things I consider
being a mistake taken over from C#
and Java like overwrite and final
which I believe shouldn't ever
have made it into C++ standard.
Debatable, see in the breaks.
We can have a fight.
And finally it goes
closely in that direction.
I will have later some slides on that.
But if you do need clean
up resource release,
use or write your own RAII classes.
And that's one of the few places
where you have a destructor
that's not defaulted
or just not existing, not
specified, not declared.
Most view types should have
either defaulted destructor
or not declared at all
which is even better.
People have fun.
So unique pointer.
Who has not heard of unique
pointer so far in this room?
Okay.
There are people who propose
unique pointer as generic RAII.
My opinion is don't.
A lot of operating
systems or resources are
represented by handles
which are trivial types,
which might fit to a pointer or not.
Sometimes they are even pointers.
Unique pointer requires
that your pointer type
is a nullable pointer.
So you can set it to null pointer
and you can compare against null pointer.
And usually when it's comparing equal
with a null pointer when
it is a null pointer,
the deleter function is not called
from the destructor of the unique pointer.
This example is copied from a blog post
and it's about a Windows handle,
I'm not a Windows
programmer but I don't know.
And I believe fortunately
invalid handle value might
be zero, but you never know.
It might even be minus one cast to pointer
or zero or less than 32,
and you cannot compare
a pointer to minus one
so it's interesting to
get what you get there.
And the automatic
non-running deleter object
in the unique point of this structure
is not actually working.
So don't.
There's another Stack Overflow question
I wrote an answer that is
not the top answer yet.
Unique pointer for file pointers.
This looks quite innocent.
You have a file, that's
good, it's a pointer,
and you have a function pointer that takes
a file pointer and returns an int
which is the signature of F close
according to the standard
library definitions.
You open the file and then
automatically you close it.
And the problem is this one.
We are not in C.
In C we don't have overloading.
So take off your dress
of a function eight.
Perfect.
Always works correctly.
Sanctioned by the center.
In C++ every function
that is spelled out
explicitly or implicitly,
in the C++ standard library
you are not allowed to take
the address of that function.
I think it might be worth it
that a CPPCon or a CPP Now talk
on why that is that case.
Just believe me, it is not.
And there are people in
the standards committee
who know, and yes.
The thing is it might be defined
in your standard library
implementation as a macro.
It might have additional parameters
that are defaulted for
your usual use case.
So standard only allows
you to call fclose,
not to take the address of it.
And the good thing is the default value
of a failed fopen call is a null pointer,
and that's a nullable pointer,
so files is a nullable pointer,
so at least the mechanics
of unique pointer work.
The original answer to that question
on how to use unique pointer.
The five pointers actually
refers to CPP reference,
but it doesn't spell out the
version of CPP reference.
After people complained no CPP
reference is wrong as well,
that was easily changed to be correct,
and they introduced a special function
called closed file in their example
that calls fclose which
is sanctioned and good
and use that close file function
with this irregular user level function
where you can take the
address in that example.
It's not overloaded so it's just for,
so they use closed file as the
unique pointer deleter part.
Another option is to pass in a lambda
that calls fclose which is also
sanctioned by the standard.
An even better version
would actually create
a class with a over load a call operator
that calls fclose because that class
could then be used, instead
of that pointer thing,
as the unique pointer's deleter object.
And then if it's a class without any state
it's an empty base class
and you get empty base class optimization
in the implementation of unique pointer
making the unique pointer
as big as a file pointer
like the regular unique
pointers are as well.
I don't show that because that's,
again, the same story
showing the deleter object
for free and that's another talk already.
Now what do we actually want to get to?
Unique resource.
That's a generic RAII wrapper,
and it can be used for integer handles
like file descriptors.
Well, it's a little bit cheating
because for files we already
have file stream object.
But sometimes you might actually
want to spell out, specify things
that you only can do via the posted API
that's given by C like
the open system call.
You get a file name, some options,
and the permission bits
read/write for everybody.
And you want to close that.
And see, this is C++ 17 code.
We have class template argument deduction.
So the type of the handle
and the type of the deleter object
which is a lambda
actually here in that case
is automatically deduced
and the corresponding
unique resource is created.
And to obtain the handle you
have to use get to get there.
Get it.
So you break the encapsulation.
And that's where you see, okay, maybe
that unique resource is some shady thing.
Whenever you write get in code
in the standard library code
it means you have some
breaking of encapsulation,
or danger lurking.
Unicorns around the corner,
just around the corner.
Okay.
In April 2013 C++ standardization
meeting in Chicago,
I believe, Andrew Sandoval
provided paper number N3677
consisting of four suggested classes,
scoped_function,
scoped_resource_unchecked,
scoped_resource, and unique_resource.
The scoped part is, in the classic sense,
like scoped_pointer that
we have in Boost for ages,
cleaning up at the curly
brace at the end of that.
And his motivation was
all the kind of handle things
that they had in their
systems were cleaning up,
was a separate set.
And whenever you got an
exception you have problems.
Good.
Some of the things in his motivation was
on unique_resource you have these
constexpr deleter functions,
whatever that means in that sense.
Actually it was some kind of magic,
so we could actually
use the function pointer
of the deleter function
as a template argument.
You can have pointers
as template arguments
that can have integers.
If that pointer is somehow
global known at link time,
functions usually are
globally known at link time.
Well, I was sitting in that review meeting
in the, when was it?
It was still I believe
library working group.
We didn't have library evolution then.
And I said, "I'm a big head.
"That can be simplified."
Now that's a story of my simplification.
This can be simpler, so I reduced it
from four classes and five factories
to one class and two factories.
Cool, huh?
I was wrong.
(laughs)
Then I attended the talk
by Andrei Alexandrescu,
CPPCon 2015, on uncalled
exceptions and scope guards.
Anybody been there?
Seen it on video?
Okay.
Eye opener, yeah.
We can have scope guards that
do something interesting.
I'm still not sure if
it's too good to have them
but they are in the paper.
So uncaught_exceptions.
A new feature in C++ 17.
The first compiler is
actually providing it.
Great, we can try it and play with it.
Then came Eric Niebler,
famous speaker here and actually
even one of my master programmers,
and he told me, well, this
can be even more generic.
I made the assumption of, okay,
my resource types are handled.
They are trivial, copyable,
I don't have to care
about moving them around,
it just works.
And whoever does something bad with them
gets what he deserves,
or what she deserves.
No.
Eric said, "We can do it better."
The thing is it's quite
hard to do it right
as you can see from the timeline.
Then came actually compilers
as class template argument deduction.
Yeah.
No more factories required
except for a single one
that serves a specific purpose.
If constexpr were actually working,
make it even simpler
even in the specification
of the feature, we can use if constexpr,
and I'll show you in a few minutes
how that is employed.
And nasty me I found a bug
in my own specification.
Great.
You see, that bug was in there
at least half of the time so far.
Nobody recognized it.
It was about double releases
which is better not happening.
Double release, bad thing unicorns.
And I'm not speaking about the nice
fancy unicorns that
little girls play with.
I'm talking about Charles Stross unicorns.
Anybody reading Charles Stross?
"The Laundry Files"?
Those unicorns are really nasty beasts.
And then there was a library
working group meeting
in August this year.
And here's some feedback,
and I show it to you how
that came back to me.
I couldn't attend that
meeting, sorry for me.
So my first attempt on making it simpler.
I assume sanity in template argument,
and that was the time when I
just wrote the apply paper.
Or maybe it was even put
in the standard in C++,
at least it was written on
the paper on having applied.
There was an example for integer
sequence into the standard.
Applies call of function and take a tuple
and pass all the tuple elements
as the function arguments.
Good.
Being a big boy like all our engineers
that I train usually,
the hardest thing that you just learned
you want to apply it in series.
I applied, apply.
Again implementation,
thought everything is well behaved.
If you have multiple resources,
everything works fine.
Release is not a problem.
And we have a single deleter, lambda,
or function that takes all
the resources as arguments.
That's something.
Well, it turned out that
simple solution was too simple.
Then came Andrei.
He said in the slides
no need to add a type for
an occasional RAII idiom,
just scope guard it.
Is that a good idea?
Does adding a type actually hurt you?
C++ has very strong and interesting types,
and writing a type is not that much work.
If your IDE might create
the struct for you
when you spell out the
time name like ours does.
Andrei's solution use interesting macros.
Who loves macros?
The interesting macros is something I hate
and all IDEs hate because
they have a boundary
of the macro expansion
that is not a syntactic element.
If the macro looks like
a function call but isn't
something that's syntactically
in the expression,
it's very bad for IDEs to parse it well
and represent it well internally.
It's not impossible but it's nice to them.
Be nice to your IDE
then it is nice to you.
But he gave me the idea
of having a scope exit
that runs whenever the
curly braces is there,
a scope fail that only runs when you leave
the scope with an exception,
or the scope's success that only runs
when you leave the scope
without an exception.
And the anchor exception mechanics
is actually what made that work.
And for those who are curious,
that's his macro on scope fail.
And there's some magic happening
and it ends with a lambda that's half done
capturing everything by
reference which is dangerous
or at least surprising sometimes,
and tries to do it well.
So I was saying all resources are same.
Not really.
If you write generic code,
you don't know what your users pass to you
and they might not even
do it intentionally.
Just capturing something
interesting with the lambda
might end up making that
lambda behave interestingly.
So what happens if a
resource throws or move?
That's a corona case
where you can say, okay,
someone who gets that
gets what he deserves.
That's not something you do running.
That's not the nice unicorn,
it's the bad unicorns.
But maybe it might not actually move
but it might copy when
you say I want to move it.
And copying might actually use resources.
And if you can't get a
resource copying fails.
And the interesting thing
is there is a nice query
in the standard library
called move_if_noexcept.
The problem is if that is
not copied constructible
it will try to move anyway.
Even if move might throw.
If it's not copy constructible
but move constructible,
but the move constructible is throwing,
you end up interesting things.
Or maybe my logic is wrong.
But nevertheless throwing moves are bad
and copying might fail, that's my story.
So Eric, my programming god,
came up with an infrastructure
to safeguard against that problem.
He invented a box type where you can
have either copying or moving
into that type generically,
and to actually construct that externally.
You have perfect
forwarding and guard object
that is released when everything went well
when the constructor body runs.
And that's interesting mechanic,
and you notice on the post to
understand everything of it.
It's just there.
And the thing is you need to jump
many hoops for fail-safe generic code,
and that's the current
version and the original one,
even it was by Eric,
had some time a little
bugs in it that we found.
How things fit together?
There's that scope_exit generic wrapper.
It constructs an exit_function object
from the function that is passed in
as the constructor argument.
It's actually perfectly
forward and exit_function
is such a box object.
And it gets a lambda or a function object
that is run when this copying
of the exit_function into
that new box object fails.
And if everything is fine nothing happens.
That's also important, no double releases.
And that scope_exit and it should execute
the exit function,
it's obtained from the box and run.
And if it should execute or not
it dependent on which kind of
scope exits, scope guard
you're actually doing.
Either the scope exit, scope
fail, or scope success.
So if the move constructor of
the exit function succeeds,
the contractor body runs and releases
the move_from element so
it doesn't double delete.
That's good.
Otherwise if the move or copy fails
you get the original in tact.
And if you don't understand
what I just talked about,
I might not even understand it myself,
the message is don't try at home.
It's just hard to do that.
That's the biggest reason
why a thing like that
should be in the standard library,
so that the big brains
are able to implement it
and you just use it.
Because doing yourself in a generic way,
I learned it the hard
part from my brevity,
bravery in 2013.
It's not simple or easy.
Now, how can you figure out
if you have a bug in that?
You test for insanity in
the template arguments.
And you write never nasty code,
you would never write at home
just to have your test cases
that figure out the bad
corner cases in your code.
Function objects that
throw and copy or move
and all the kind of variations.
Interesting.
Resource objects that
throw and copy or move
or even throw and move if
you don't wanna have that.
Resource objects that
cannot even be assigned to
which actually checks the CNI
of the reset functionality,
is it available or not because
you don't wanna reset resource.
You cannot assign to the resource which is
there is an issue with
a simple handle type,
but whatever resource
you might put into that
it's generic, we don't
know in that library.
They're non-assignable resource.
Now to give you an example on how
the complexity works out.
Fortunately we now have if constexpr
so we don't have to
to overload a resolution or lift
so senile around that thing
so we can actually write.
If we have an assignment,
a move assignment,
we first check for self-assignment.
That's essential because we don't want to
prematurely release our
resource that we hold.
We release it by calling
reset which is noexcept.
That's one of the guarantees
we ask for by the providers.
And that checks the static asserts.
If both parts of our unique resource,
the resource and the deleter object
are no throw move assignable,
nothing bad can happen, it just works.
So we move assign them.
If one of them is not move assignable,
we first do the copy because that leaves
the original resource, the
move from object in tact.
And then move the other
part that is safe to move.
So we get an exception before
we put the other object
in the move from state.
And if both are non-movable or
non noexcept move assignable,
we copy both of them where
the original stays in tact.
And only then we actually
set the other into don't
destroy the resource
because then everything is fine,
otherwise the original object stays
in a means that is not moved from
so it will actually destroy the resource.
You see, we have two resources,
four cases to deal with
to be exception safe
and sane in the move assignment.
And managing just two resources alone
that can individually fail to move or copy
is almost insane to follow that.
Just figure out what you get
when you have three resources
that individually can fail to move
or copy or to initialize.
Don't go there.
Don't do it.
So that's the reason why you should employ
unique resource from
wrapping your own resources
or write your own RAII classes
only for a single
resource, not for multiple.
Doing it for multiple is a pain
and too easy to get wrong.
Now I promised you the
backend specification.
That's the specification
of the move constructor.
We just have the move
assignment of unique resource.
And who finds the bug?
It's again the same trick.
If something is move constructible
without throwing an
exception, we do the move,
otherwise we copy and the
same with the deleter object.
And if that throws an exception
we actually call the deleter
with the already moved resource
and release the right hand side
so it's no longer calling the deleter.
And finally we memorize that
the execute on destruction
was on the right hand side.
Anybody found the problem?
So you actually might not run the deleter
when you delete the object.
Yeah?
(unmiced talking)
Let's say you don't
duplicate the resource.
You move the resource,
the move constructor,
but you run the right hand
side deleter in that case
and release it.
So the resource in that,
the move from resource is okay,
and you cannot copy the deleter.
You still delete the resource
because everything moved.
But the bug is this code doesn't consider
if the right hand side
was actually needing
to delete the resource.
It was unconditionally
deleting the resource,
and that's the bug there.
If the right hand side
was already released,
there's no work to do.
And this would cause a double delete.
So only when the right hand side
need to actually clean
up, the clean up is done.
And you see the node is extended again?
This mechanism ensures no leaking
and no double releases
which is not to easy to spot.
It took more than 10
revisions to find that.
How do you test for such nasty things?
That is a test case.
It violates all good software
engineering practices
but it's only for the test case.
And it actually has a deleter object
that throws on the second copy
on every second copy
but it's only used once
in the test case.
But actually that made that test case fail
when you forgot that thing.
And I wrote the test case to make sure
we never introduce that bug again.
And do you see,
don't do that in production code.
But who has not seen things
like that in production code?
Global state.
Never ever?
Lucky.
More surprises.
We got a feedback of BSI
that ask us to add that note.
If the exit function of a scope_success
or scope_exit object refers
to a local variable of the function
where it is defined, e.g.
as a lambda capturing
the variable by reference,
and that variable is
used in return operand
of that function, that variable
might have already been returned
when the scope guard destructor executes,
calling the exit function.
This can lead to surprising behavior
because it might be moved from state
and you access it expecting it having
the original state or some state at all.
You might even call a member function
that you are not allowed to call on it
when it's in a move from state.
And I tried hard to figure
out a version that works.
And fortunately the
implementation of the string class
that I had had a destructive move.
But you have to guarantee that
is actually copied or moved,
and that's by the parenthesis
I put around the return.
Never ever do that at home
because it hinders all
optimization of copying.
But what we expect would be
that the length that you pass back
from the access returned
from same function
is actually the actual
length of the string,
but it isn't, it's zero.
Because you access the
string in the lambda
of the scope exit_guard.
Only after it has been moved from.
So the cleanup of the string object
is not done yet because the
sequence of the variables.
But it's moved from the return statement
already has been processed.
So we get this test case parses.
And remember Andrei's macro passed all
variable by reference to the lambda there.
Danger lurking, or let's see,
it's not the unicorn, it's more like,
oh, there's a flower there.
I didn't expect that.
A nice one or a stinky one.
Final feedback.
You're not supposed to be reading that.
Just all the pinky parts
is where the feedback,
the protocol that was taken,
has some dot dot dot in there.
I have not figured out everywhere
what dot dot dot means.
Sometimes it meant mumble mumble mumble.
I don't understand it,
or maybe I wasn't fast typing enough.
I wouldn't say that the
note taker is guilty.
It's just it's very hard
if you're not present
to make use of the feedback you
get from the working groups.
So we will not see that anywhere else.
I'm sure the reviewers and
the note taker did their best.
It's just not easy to process that.
And especially because it's
an intricate, tricky feature,
we very often get feedback
that is opposing in different meetings,
and maybe in the same meeting
which also tells a story about
why it's taking those long.
What's left?
Oh, we could do things like
empty base optimization.
We have empty deleters to make the unique
resource object smaller.
We might get around that
with the no unique address
for the deleter object.
At the moment it wouldn't work,
but maybe we can, I'm not sure if.
Let's say I leave that task to the,
send the library implementers.
At least that's my take today.
nodiscard, we cannot use
nodiscard on constructors
which is a pity because especially
the unique resource in the scope guards,
especially the scope guards,
you want to have nodiscard
on the constructor
because if you don't
declare a local variable
it's like immediately calling
the lambda or the deleter function.
That's not what you want to do.
Like this.
And I need to incorporate
the final feedback
especially the standard
is a moving target.
All the section names of
specifying the behavior
or the semantics of a library function
have changed the name,
and sometimes even split the semantics.
So that's busy word to getting
the spec according to the
current rule in the standard.
Now should you write
your own RAII wrapper?
In my opinion, yes.
It's good to do your own abstractions.
Don't cheat.
Even if Andrei says no need to add a type.
For occasional RAII it needs.
I think there's nothing
that is occasional.
Either you code this deliberately
and then do it right or not.
On the other hand things
like finally or scope_exit,
they have a smell of a hack.
Maybe sometimes you want
to stand that smell,
but not that often.
Don't sprinkle it in your code base.
It's like you need raw pointers in C++
to implement things like unique pointer,
but you don't want to have raw pointers
in your own code base.
And this is the only example from Andrei
about the kind of transaction semantic
where you remove a temporary file
that you no longer need when things fail
or that's partially written.
But that's a nice code.
You don't have to try
catch and things like that,
but I'm not sure if that's that common.
And and it's nice to encapsulate it
in that single function
and not spreading in your code base.
I'm happy to learn more
about using scope guards
like scope_fail throughout your code base
and being happy with that.
Andrei seems to be happy about it.
I'm not sure if that's really
the best thing to do in all the cases.
Now what should you take away?
If you don't know RAII,
learn about it and use it consciously
for all kinds of resources
that you acquire and have
to release in your program.
Understand your own resources,
like, what kind of resource is it?
Is it a react resource, which is rare,
and incorporates all kinds of problems
is sharing means you mutate it
from different places which leaves
the databases without a protection?
What lifecycle does your resource have?
Is it local to a scope?
Do you have to extend the lifecycle
of the resource keeping around
like the unique resource that you turned
from factory or pass along
the coal chain up and down?
What amount of resources need to program?
That's always a problem.
I know a server and apps
that just have to be restarted.
A good server runs 24/7 for years
without having the need to restart.
I've created software
like that with my teams.
It's not easy, but the ops
people love you for it.
Oh maybe I have to say, I'm sorry.
I've been to a conference
two weeks ago, or three,
where people were saying,
yeah, you get memory leaks
and stuff like that.
No, in C++ you don't have to.
And if you write code
that has memory leak,
you're doing bad things.
Don't.
We have the facilities
to easily manage that
that it works.
And that's true for all
the resources, RAII.
Do it.
There's no excuse at all.
That's not even me being despotic.
To have leaking code in C++.
It's hard if you do
more than one resource.
But using a thing like unique resource
or other RAII wrapper,
you can easily combine
them as members in a class,
and there the semantics of
C++ is using constructors.
If constructing the object
fails halfway through,
all the cleanup is done
automatically for you.
There's no try catch required.
It just works.
In your own classes,
wrap each resource member
acquired individually in an RAII wrapper
to achieve that transaction
semantics on failure of one.
And do not naively use scope guards
throughout your code base.
Build proper RAII abstractions.
Beware of pseudo dangling references
to moved-from variables in these lambdas
that run on scope exit.
And the teaser for tonight, Tool Time.
We demo our IDE.
We have a couple of hats and
some Swiss chocolate as well
to give everybody.
So if you can stand up as long,
I'm not sure if I can make it,
8 something, I'm not
sure if it's 8 or 8:30,
Tool Time for Cevelop.
And if you have other
questions about that,
feel free to contact us and go for it.
That's not what I wanted.
Questions?
Use a microphone, that makes
it easier to record it.
- One of the main cases that
I was thinking for using this
and I've been hearing about it for years,
just like in your proposal,
is for interacting with the legacy C code.
What you might call a (mumbles)
think of as the resources,
files, or database (mumbles)
uses some big resources.
Well, the signal really
works by some initialization
and it is (mumbles).
Now, if I understand
your resources correctly
you have several things that kind of
converting legacy C code into
properly managed C++ code,
it really amplifies the code because
first of all you have to get
how really the (mumbles)
at least the proper thing
for increased conversion,
especially if you have a wall of API.
I know this is (mumbles).
- We had that and it got removed.
- I would really, really want that,
just have a wrapper, you know.
- Tell the committee.
- The other thing is, I think,
having the deleter is part of the type.
It's really problematic if we're trying
to think the (mumbles)
resources are numbered.
So we want something that
behaves like a C pointer.
But if it's (mumbles).
- I think someone will
answer that question for me.
- [Man] I'm going to answer that.
(unmiced talking)
It's not a big issue because there will be
a type going into standard library
called (mumbles) which
is the type reference,
a hybrid typing literature for functions
that has reference statics.
So if you use a (mumbles)
it takes off the eraser,
then you get all these winning resources
at the same time.
- The thing is--
(unmiced talking)
So maybe let me summarize.
There was an issue about, okay,
making the deleter part of
the type gives you problems
because you have too many types then.
There is type erasure
available coming in '20?
And in addition
you can use possibly by reference.
That's one of the corners
I didn't explain to you
because the talk was too long already.
You can actually pass a reference wrapper
or actually you can pass
a reference to a function
and it will keep a reference
wrapper around to some of that.
- [Man] That doesn't solve the type issue.
- Yeah, it doesn't solve the type issue,
but the reference wrapper is
another dimension of complexity
that I didn't talk about today.
So there's more lurking.
- [Man] Okay, my comments.
May I go back to your slide
showing the loss of (mumbles) constant.
- I don't get that?
- [Man] There is a slideshow (mumbles).
- Oh that one.
Oh the--
(unmiced talking)
Yeah.
The one with the many cases?
That one, okay.
- [Man] To be honest
this is a bad (mumbles).
The reason is that it duplicates
the conditions, right?
(unmiced talking)
This line is the same as that line, right?
So what we should do here is to
create a bool constant in this fashion.
So you have a function that accepts
two bool constants arguments.
And you disperse it
against your conditions
so that you have (mumbles).
- Have you seen the
code how it was before?
- [Man] Yeah.
- That's exactly how it was,
and then someone suggested
using if constexpr.
- [Man] No, well.
This piece is not going
to specification, right?
- The specification is as if
and it's easier to specify
with the if constexpr,
but you don't have to
implement it that way.
- [Man] Implementation wise I would be
using bool constants in this fashion.
I know it (mumbles).
- You're free to do that.
I think we need to catch up, time's over,
but maybe one last quick question or?
- I don't know if it's a quicker.
Basically, like, I'm
not sure how (mumbles)
when you're talking about what Andrei did.
I feel a little bit the
opposite in the sense of, like,
sometimes I get, I've used
scope guard for years,
and I sometimes get mileage
out of it when I talk.
Not very often.
Usually though, I mean,
you said it yourself,
like, usually the resources
are handling use copy,
and usually, actually
the deleter is stateless
and you don't have to
think about moving it.
So I have written many
of my own RAII classes,
and I've actually
personally never encountered
a single case where I had
to think about any of this.
It was always actually very
easy to write it yourself.
I mean I don't memorize different codes.
So I'm just curious, like,
how many times are we
actually gonna be in cases
where writing the RAII class yourself
is so hard to do correctly because
you really could throw
every time you move.
I almost never see that in general.
It just seems to me, like, a
very, very tiny quarter case.
And, like, scope guard
and moveable scope guard,
just the landed (mumbles) that's immovable
could've easily been
standardized instead in 17
because it's, like, 10 lines of code.
And once you can't move
it, it's dead easy.
And that's it, I don't know.
- That was my opinion
five years ago as well.
- [Man] Now you don't think so anymore?
- Well, I was told otherwise.
- Okay, cool.
I was just curious.
- Library evolution
didn't like it that way.
And thank you very much.
See you tomorrow or tonight.
(crowd applauds)
