CppCast - Trivially Relocatable
Episode Date: January 10, 2019Rob and Jason are joined by Arthur O'Dwyer to discuss board games, his 3 ISO C++ papers and much more! Arthur O'Dwyer started his career writing pre-C++11 compilers for Green Hills Software; h...e currently writes C++14 for Akamai Technologies. Arthur is the author of "Colossal Cave: The Board Game," "Mastering the C++17 STL" (the book), and "The STL From Scratch" (the training course). He is occasionally active on the C++ Standards Committee and has a blog mostly about C++. News Add an interactive command line to your applications "Modern" C++ Ruminations Initialization in C++ is Seriously Bonkers cpp_feature_flags Arthur O'Dwyer @ColossalCaveTBG Arthur O'Dwyer's Blog Links Adventure Colossal Cave: The Board Game CppCon 2018: Arthur O'Dwyer "Return Value Optimization: Harder Than It Looks" C++Now 2018: Jason Turner "Initializer Lists Are Broken, Let's Fix Them" CppCon 2018: Arthur O'Dwyer "An Allocator is a Handle to a Heap" C++Now 2018: Arthur O'Dwyer "The Best Type Traits that C++ Doesn't Have" CppCon 2018: Arthur O'Dwyer "Trivially Relocatable" Trivially Relocatable on Compiler Explorer P1154R0 Type traits for structural comparison P1155R1 More implicit moves P1144R1 Object relocation in terms of move plus destroy Mastering the C++17 STL Sponsors Backtrace Hosts @robwirving @lefticus
Transcript
Discussion (0)
Episode 182 of CppCast with guest Arthur O'Dwyer
recorded January 9th, 2019.
This episode of CppCast is sponsored by Backtrace,
the turnkey debugging platform that helps you spend less time debugging
and more time building.
Get to the root cause quickly with detailed information at your fingertips.
Start your free trial at backtrace.io.cppcast.
In this episode, we talk about initialization and C++ feature flags.
Then we talk to Arthur O'Dwyer.
Arthur talks to us about board games, his podcast for C++ developers by C++ developers.
I'm your host, Rob Irving, joined by my co-host, Jason Turner.
Jason, how are you doing today? I'm all right, Rob. How are you doing?
Doing okay. It's like first full week of the new year now, right?
Yeah. Yeah.
So getting back into the normal flow of things, get back in school and all that.
Good stuff. And time for me to make sure everything's ready for uh c++ on c less than a month and
yes that's well i i leave february 1st i honestly can't remember what day the conference actually
starts i'm more paying attention to my own schedule right and uh teaching a class there
and giving a talk and it is official now that i am also giving a class at Core C++, the one that's in Tel Aviv.
Right.
Which I don't think I had mentioned that yet.
June or July, I think, right?
It's May.
May, okay.
So it's immediately the week after C++ Now.
Okay.
Which means I'm probably not going to C++ Now, because it would make for a very tight trip.
Yeah, that'd be a lot of trouble.
Yeah. Okay, well, at the top
of the episode, I'd like to read a piece of feedback.
This week we got a tweet
from Daniel
Palastrelli,
and he wrote,
I'd like to have feedback from your listeners about my
modern C++ interactive command line
library, and he sent us a link where
he actually posted this on Reddit.
And it seems like he actually got a lot of
upvotes and a decent amount of comments
right here on Reddit.
And I'll put this link in the show notes.
But it's an interactive command line
library for C++
applications. And it looks
nice because it's for, you know,
it's interactive as in you're not just passing
command line parameters and then running it.
You can continue interacting via the command line while the application is running.
So for applications that need to run that way and be interactive,
it seems like a good library.
Yeah, the first upvoted comment on Reddit is like,
oh, you should record a session with the ASCII Cinema tool.
And oh, that's a great idea. And so I saw that a couple weeks ago in the articles posted on Reddit is like, oh, you should record a session with the ASCII Cinema tool. And, oh, that's a great idea.
And so I saw that a couple weeks ago
and the article was posted on Reddit.
So I was really hoping that there was one now
and I don't see an interactive video of it.
Yeah, it'd be nice to see a GIF or YouTube
of the library in action.
Yeah, that goes a long way for people
that are just checking out something real quick.
Well, we'd love to hear your thoughts about the show.
You can always reach out to us on Facebook, Twitter,
or email us at feedback.cpcast.com.
And don't forget to leave us a review on iTunes.
Joining us today is Arthur O'Dwyer.
Arthur started his career writing pre-C++11 compilers
for Greenhill Software.
He currently writes C++14 for Akamai Technologies.
Arthur is the author of Colossal Cave, the board game,
mastering the C++17 STL, the book,
and the STL from scratch, the training course.
He is occasionally active on the C++ Standards Committee
and has a blog mostly about C++.
Arthur, welcome to the show.
Thank you. Good to be here.
How did you make a board game about Colossal Cave?
Or maybe you should explain what Colossal Cave is
for our listeners who are too young, like Rob.
Yeah, that's fair.
I don't know what that is.
Yeah, the one without a beard.
Well, Colossal Cave, or Adventure,
as it was originally called, I guess,
it was just Adventure because it was the original adventure game.
It was the only text adventure. You go called, I guess. It was just Adventure because it was the original adventure game. It was the only
text adventure.
You go north, enter cave,
get treasure,
kill troll with sword, that kind of thing.
It was the original. Originally, it was the
only one, and so it was just called Adventure
or Advent.
Then
it was widely distributed and imitated,
and Infocom, these guys at MIT,
picked it up and made something called Zork
that was kind of based on it,
and that turned into a whole series
and a business for them.
But Colossal Cave was originally just
these two guys who, one after the other, went and created this iconic text
adventure.
I don't know.
You should play it.
It's good.
Okay.
You made a board game, though, out of it.
Yeah.
So this was back in around 2012, 2013. 2012-2013. And I had been playing a lot of
the
Looney Labs game
Back to the Future.
I'm big into board games. I do a lot of
I didn't know there was a Back to the Future
board game either. There is. Well,
Back to the Future card game based on
Crononauts for other board game
nerds in the audience.
And I highly recommend it it's
it's fun um and it got me thinking that hey i could take this mechanic and and kind of uh
massage it to uh to put it on top of this other thing that that i was really into um adventure
um and so it's a a uh essentially, uh, cards for different items and treasures
that you find in the cave.
And the idea is you go down into the cave and you get treasures and you come back, um,
and the first person to get three wins, um, and there's a map, uh, you know, a board with
the locations that you move around on and you have to be in certain places to play certain
cards or to get certain items.
And, um, and it's a, uh, a uh a large element of take that of uh you know
you think you're you're gonna get this treasure back up to the surface and someone else has the
bottomless pit card and suddenly you're in a pit and you lose your treasure so um and so i i put I put that on Kickstarter and got more money than I thought I was going to get.
Oh, wow.
Like $15,000.
So not $6 million, but enough to print one run and distribute it.
And you can buy it on amazon used at this point um yeah and uh you know
maybe in a decade or so maybe i'll do a version two but uh um but it was fun you know i think
you are the first guest we've had on who's had a successful kickstarter or a kickstarter of any
kind really agreeing with me i think i mean i don't recall ever bringing it up with another guest
yeah there's one other guest that we've been talking about getting on who has had a kickstarter
but we haven't had him on okay so i i've got to ask like for people who are considering that it's
completely off topic but on topic for your bio what uh like how much of a pain was it to like
send all the rewards that kind of thing like uh 2000 you said 2012 ish yeah so that
would have been that's a pretty early kickstarter right yeah yeah it was uh it was when kickstarter
was like the new hotness like it it was like i wasn't like a pioneer or anything but it was like
right after the pioneers and they were like proving that okay yeah you can do this and everyone's like
oh this is awesome i'm gonna do my own kickstarter um and what actually happened in my case was there was a
game publishing company um that uh started started up as like a spin-off so not really a spin-off of
kickstarter but like exploiting kickstarter rightelling the picks and shovels to the gold rush. And they contacted me
because they were just sort of trolling Kickstarter
looking for projects.
And they said,
we would like to take 90% of the money
in exchange for doing your fulfillment
and coordinating with the factory and so on.
And I said, that sounds awesome.
Right.
Because I wanted the thing to put on my bookshelf.
I didn't really care about the millions of dollars
I was going to get by selling this thing.
So they picked it up.
And so they did all the fulfillment and everything.
And so that, from my point of view, worked out very easily.
From my side, i just needed to
sort of make a spreadsheet of everyone who had signed up and what they should be getting and
um you know and then send it to them and they seem to take care of it pretty well
um yeah this is totally off topic but i will say the one uh thing that uh was a little bit of a snafu was I had originally planned to do the game and then an
expansion, and you could pledge extra money to get the expansion. But it turns out this is not
really a good model for a Kickstarter, to have one tier where you get one thing, and then the next
tier where you get that plus something else, if it's an expansion, because now, okay, based on the number of pledges,
you've sold 1,000 games and 500 expansions.
What do you do with the other 500 expansions?
So unless you're doing a lot of volume, which I wasn't,
what we ended up doing was saying,
okay, let's just put the expansion in the box with everything else,
because it's actually cheaper to just make one thing.
And so everyone got the expansion.
And then, of course, everyone who was in the higher tier
was like, hey, we paid extra for the thing,
and then you gave it to everyone else,
so we ended up giving them gift certificates
to buy other games through the Game Salute store.
So they ended up getting more than they paid ended up uh getting more than they paid for
everyone got more than they paid for which was great yeah i guess that's good for everyone for
these starter backers yeah yeah okay well we uh to go back on topic have a couple of articles to
discuss yeah that was interesting uh feel free to comment on any of these though and then we'll
start talking more about the proposals
and C++ work that you've been doing.
Okay?
Yeah.
Okay, so this first one kind of calls back
to an article we discussed last week with Izzy.
This is Sean Parent's response,
which I think we actually referenced
when talking about the other article,
to the post by Ares about modern c++ ruminations
so yeah this is sean parent's response which i guess several people in the community were asking
him to respond to this post and um i think we kind of had similar things to say about it last week
which is yeah the stuff he's talking about is important c++ compile time and you know bail time
is important but uh you know the post that he was picking apart,
the Eric Kneebler ranges post or example
was just really not a great example code, right?
It seems to kind of be the conclusion
of everyone on the internet
was that Eric's example is not a great example.
Yeah.
This IOTA thing though,
Arthur, I'm sure you've been following the iota thing
yeah it's it's like a guilty pleasure right um there's something no one should be it's like
the kardashians no one should be paying attention to iota but that's the one thing to come out of
this um i mean i gotta agree with the original post, though, more than Sean Barrett's side.
It's not really sides. Everyone kind of is agreeing. Everyone's very reasonable people.
But, you know, the upshot does seem to be that, you know, ranges takes eight minutes to compile.
And the examples that purport to show how awesome it is end up not being good examples.
Like, I want to see
a good example if the consensus is always oh wait that wasn't a good example like someone should
show a good one there was a tweet an article ah it was a couple weeks ago where someone said
i showed ranges to my new c++ students just a concept, like didn't like show them like a specific example.
And they came up with all these great examples.
And it was a couple of things listed.
And I cannot for the life of me remember who posted that
and when and where it was.
But maybe we just need people who don't know what they're doing
to come up with the best examples.
And then we need someone who's a super duper expert
to look at those examples and figure out
if they're right or not, right?
Or if they have subtle dangling references.
Well, hopefully they don't.
Threat and safety, you know, but...
Oh, sure, we all hope we don't, right?
For any program, you can say, I hope it doesn't have bugs, but...
Yeah.
I'm skeptical.
So I guess we should give a little bit of an...
Just, we kind of talked around IOT skeptical. So I guess we should give a little bit of an... We kind of talked around IOTA.
Basically, some people are saying,
well, the history of what IOTA means is obvious
and everyone should know it effectively.
And other people are saying,
well, everything you just said is wrong.
That's not much of a summary.
No, I think Eris's original blog post said
something with a bit of exaggeration for effect.
Said that IOTA is an example of the cancer that is C++ today, where they're just making up these, look how smart I am, IOTA stands for this thing from APL.
And everyone should just obviously know it.
We don't call it generate sequence.
We call it IOTota because we're cool right and sean parent was saying well you know really you know yeah you should know apl because it's
important as a craftsman to to understand the the history of the profession and and you know like
yeah you should know about iota but um which is true as far as it goes but you know there's always
going to be more people who haven't learned that particular thing
today.
Everyone does know what generate sequence means
because they know those English words.
Now you have to
know two things. You have to know what it does and also
why it's called IOTA. It would be simpler if it weren't called
IOTA. It just would be simpler.
But, you know, should we argue about it?
No.
If you all will indulge me for just a second, I'm reminded of signs that we just got back
from Hamburg right before Christmas.
Hamburg, we're in Germany.
At the Christmas markets, there's signs that say POM.
P-O-M-M-E-S.
This is the French word for apple.
Yeah.
Right?
What does that mean?
That means French fries to an American. Why? Because in French,
they say pommes frites, which means literally apple fries. But that's a shortening of pommes
de terre frites, which means apple of the earth, which is potato fries. So it starts from a
shortening to a shortening to a shortening. And now we have
the French word for apple on signs in Germany, meaning fried potatoes.
So that's what Iota made me think.
One more thing I just wanted to point out with this article that I thought was interesting
before we move on is that Sean Parent says that he will spend weeks writing code without trying to compile it.
And that just really kind of explains to me why Sean Parent is able to do what he does with
being able to look at some code and say, yeah, that's just such and such algorithm.
I thought that was pretty interesting.
Yeah, I never spend more than six or seven hours writing code without trying to
compile it personally.
I never go into like multiple weeks of thinking about it because I have to get past this mental
hurdle to know if the thing that I've tried so far is right.
I might end up rewriting it again, but otherwise it's difficult for my imagination to move
past that.
Okay, so next article we have another one that might
have a lot
to say about it. Initialization
in C++ is seriously bonkers
and this is from Mike
Liu who said just start with
C as a subtitle, which
I know is not going to be an opinion that we all
agree with, but there definitely
is a lot of craziness with the
C++ initialization that he
points out in this article along with the great gif that's at the point the top yes and you
hopefully you've maybe seen this gif online already if you are i love it or anything but
it's uh clips from forrest gump where i can't remember the name of the character bubba bubba
is talking about all the different types of shrimp only instead he's talking about all the types of c++ initialization it's great yes i would say the gif
is better than the article um i think the author even says that he's like yeah just just watch this
gif and you don't need to read the article yeah um it it makes like things can be very complicated.
I feel like it's making it
maybe a little bit more complicated than anyone really
needs to know.
It's a problem that it can be made so complicated.
It should just be simple. There should be no way to make
it complicated.
But a lot of these examples
I felt like were things that people
wouldn't even run into in real life.
And there's plenty of things that people do run into in real life that you could complain about.
Right. Maybe, yeah, that's a good thought there.
Let's focus on the things that people run into every day and try to make those better.
And I'll say, Jason, you had a great talk at,
I believe it was C++ Now this past year, right,
on initialization and initializer list.
Yeah.
And all the things that it, you know, it disables move semantics
and has issues with deduction.
And I forget all the issues, but I was in the room for that,
and it was highly entertaining then.
I don't know how it translated to YouTube, but I recommend everyone go back in time and go to it for sure, and possibly watch it on YouTube.
Yeah, well, initializer list, well, that's something that annoys me as a teacher.
Initializer space list versus initializer underscore list. I'm referring to the
initializer underscore list, which is
the type that is created
for you when you do list initialization
of something like vector.
It just hides too much
machinery. That's my
overall complaint for that one.
But yeah.
And then we can move on to this last article.
Not really an article. It's actually just a GitHub repo on to this last article not really an article it's
actually just a github repo with just one c++ source file but it's something that could be
pretty handy if you compile this you'll find out all the features that your c++ compiler will
support yeah that's pretty neat yeah and it'll just say like this you know feature which is a
c++ 20 feature is or is not supported.
So yeah, seems pretty handy. I only have one question about it.
At the very top, it starts with,
if in def underscore underscore has underscore include,
I don't think the standard requires that has include
is a preprocessor macro that you can test for.
And I don't know if Arthur has an opinion on that or not.
I would be very surprised if it were a preprocessor macro
you could test for.
But I did actually go and I ran this code
on Compiler Explorer with a couple of compilers
and was pleasantly surprised that it compiled.
So, yeah, I mean, all the vendors seem to agree then
that has include should be a pound to find, basically,
that that idiom should work,
which I think is great because it was not that long ago
that a lot of these header files,
they're just saying if this include file exists, then include it.
And it wasn't that long ago that including a file that wasn't supported
would have a pound error in the middle of it,
saying you need C++14 to include this file.
And then if you include it at all, your program just dies.
And the library vendors have been moving away from that.
Now they're moving to something I don't really like, which is just
no ops. You include optional
and it just
doesn't have any code in it.
Because it all has to be compiled
away if it's not in the right...
I wish there
was some way for the
vendor to actually say
well, if you're in this mode then this header
doesn't exist. And then you would actually be able to say oh okay the header doesn't exist i'll go
include a different header you know this way you have to say okay i'll include the header
it'll all get if deft out i will test this other macro to find out whether the feature was included
by that header right i'll find out whether there was any code and then i can go include boost
optional or whatever whatever my workaround is.
It's still a complicated dance, but at least it is moving to be a dance that always works.
C++ is simple, right?
Yeah.
Okay, well, Arthur, as we said in your bio, you said you are occasionally active in the C++ Standards Committee.
Do you want to tell us a little bit about the proposals you're currently working on?
Sure.
So the big one is trivially relocatable.
But I almost wonder if we should start with the smaller one.
Let's do that.
We'll go start with the smaller one, yeah.
Let's start with the very smallest. Let's do that. We'll go start with the smaller one, yeah. Let's start with the very smallest
and then work our way up.
So I have one that I am trying to push for,
which is just type traits
for this new structural comparison stuff
that's coming.
So, you know, operator spaceship, right?
The less than, equal, greater than
three-way comparison operator.
You can equals default the comparison operator, you can equals default
the comparison operator
to get the compiler to generate it for you,
and then it will deduce the appropriate
strong ordering or
weak ordering or whatever.
Weak ordering is a
dumpster fire, by the way, but
it should always
deduce strong ordering.
But
let's see.
And then if you equals default your comparison operator,
then it becomes, at least if it's defaulted all the way down,
it becomes what's called a structural comparison operator
that then allows you to use the type,
if it's appropriately constexpr,
you can actually use it as a non-type template parameter.
And so this allows you to write your own types
that are then usable as template parameters,
which is something that we have not had before.
You could use them as regular function parameters,
the constexpr functions,
but not actually template parameters themselves.
However, you could only do this
if the comparison operator is structural.
And you might say, how do I know, you know,
or how do I verify that my comparison operator is structural?
You know, equals defaulting it is not quite good enough
because if one of my base classes or one of my members
doesn't have a structural operator,
then my operator isn't structural.
And the compiler knows, of course,
whether it is or not.
But it would be very nice to
have a way that I could static assert
that this property held for my
class, because it's a relevant property.
And, you know,
rather than writing some sort of
clever code to
detect this, I would like to just be able to static assert it.
I might even have code that wants to switch on,
if it's structural, I can do this version.
If it's not structural, I do this other version.
I don't know of any use cases for that,
but just having this type trait available,
having an is, I forget what I call it,
has structural comparison, it's in the proposal.
So that's the little one.
So I guess before we move past that,
what's the status of the little one within the standards committee?
Well, I've gotten Jeff Snyder,
who is one of the principal authors of the original structural comparison,
non-type template parameter thing, to say, yeah, this is a good idea and to be a co-author. But it was
being looked at by the new LEWG incubator, I believe,
as of San Diego, which I wasn't at.
And I'm going to be in Kona and hope to be pushing some of these a bit more
there.
Although there was also some debate over it originally
that the LEWG didn't want to see it
because they said,
well, this looks like compile-time programming.
Shouldn't this go to the reflection study group?
And the reflection study group, of course, said no.
No, I would agree.
We don't want to see this.
So they ended up playing ping pong
with it for a little bit.
I don't see that as any difference.
Who has jurisdiction?
I mean, there's so many type traits, I just wouldn't see how it's different
from any other type trait, really.
I think it was more that
LEWG didn't want to
deal with it. It was a good didn't want to uh deal with it oh okay it's a good excuse
to have someone else uh deal with it um but that person didn't want to deal with it either so
um so the uh other proposal that i have going which i have uh probably the best hopes for i
think as far as trying to get it into, hopefully, C++20.
We'll see.
It's something called More Implicit Moves,
which is P1155.
And the point of this one is,
you know about RVO?
I gave a talk about RVO at CppCon,
and I recommend everyone well
yeah everyone should go watch it at least if you want to know what i'm talking about for the next
five minutes um um well it was weird because uh when i gave that talk at cpp con i actually
thought i had signed up for an hour long slot and it turned out it was a half hour slot um totally
my fault that i didn't know this going in um but
it had to be a little bit improvised at what point did you realize you only had half as much time
oh like as soon as i was on the stage and the av guy came up to me and said we're gonna need you
to get off the stage real quick you know at the end of the because the next guy's coming up and
i went so it doesn't seem normal so literally like a minute before you're ready to start your talk minutes before yeah yeah so all right it's kind of raced
through uh something but but anyway um so rvo so um the general rule of thumb these days and
really for the past couple of decades has been if you say return x semicolon um that's probably as efficient as it as it's going to get
right you shouldn't do anything weird you know you shouldn't you shouldn't say returns did move
of x like that's never going to be faster right because uh probably never going to be
sounds like you've seen my talk um well it should never be, right? Because with return X, either X is a local variable,
and therefore I should be getting return value optimization,
my copulation.
Right.
Or X is something like a parameter
or something that can't be copulated.
But even in those cases, I get what...
The standard doesn't really have a name for
this, but I'm calling it implicit move, where instead of calling the copy constructor, it
actually calls the move constructor to construct into the return slot. However, this doesn't fire
in a lot of cases, a lot of different kinds of cases. In most cases, 90% of the time,
99.9% of the time in real code, it will fire
because it will look for a constructor
that takes an R value reference, the type of X, basically.
Okay.
And then if that exists, it will call it,
and if not, it falls back to copying.
Right.
So the problems are, what if the thing that it, it will call it, and if not, it falls back to copying. So the problems are,
what if the thing that it finds
is not a constructor, but a conversion operator?
If I have an rvalue-qualified conversion operator,
it's not going to find it.
It's going to find it, but ignore it,
and it's going to use the copy constructor instead.
What if the constructor defines,
it does find a constructor, but the type of the
constructor's parameter is not rvalue reference to the type of x, but to a base type of x.
Right.
If x is a derived class, and I'm returning an instance of the base class, rather than moving
from x into the base return slot, I will actually make a copy.
And that can be quite expensive.
That was the case that I ran into in practice.
And it's covered also in the talk.
And then it needs to be an R-value reference.
So if you have a converting constructor
that takes its parameter by value
rather than by R-value reference,
and actually taking things by value in constructors is something that we're taught these days
to do.
So if you do that, then again, that's not an rvalue.
And so you'll get a copy.
And in all these cases, there's no real reason, like there's no physical reason that a copy would be better.
And there's no physical reason that the copy has to happen, you know, for technical reasons.
It's just that in the paper standard, the wording is very specifically looking for R-value references and constructors,
and not conversion operators, and not by-value syncs and that kind of thing.
So my proposal basically says, let's cut about half of this paragraph,
all of these words that add pessimizations to existing implementations without providing any benefit.
Let's just cut those words and say, here's what we're going to do now.
We're going to look it up like it was an R value. And if that works, we're going to do that. And otherwise we'll look it up as an L value.
And that's it. Just on any return statement?
Any return statement of the form like return X, where you're returning something by name.
I'm wondering if that would also apply to the issues that I've hit with returning sub-objects return x dot s or whatever um my proposal would
not change that i know that uh anthony pelucan whose name i may or may not be pronouncing right
um had a couple of proposals um going into san diego but i think they were not well received
because that is a very hard problem right it seems like it could it sounds to me like your
problem could address that though because then if the the x part of that still becomes an r value
then the dot s would become an r value and everything would work like you wanted it to
well you can't do that for arbitrary expressions for for dot maybe um but suppose i had return
like x plus x right i have a double function no, you wouldn't want to do that.
It takes x and returns x plus x,
and if it's a string,
it concatenates the string with itself.
If I turn those x's into r values,
then yeah, that would just totally blow up.
No, but the result of that's already going to be an r value,
and what you want is going to happen already.
No, because there I'm adding an L value to an L value.
Yes, but I'm saying the result of that expression is an R value,
so it's going to properly construct the return value.
Yes, but if it knew that X was an R value going into operator plus, it could maybe reuse its buffer.
Now, because you're adding it to itself, there's an extra wrinkle there,
and it probably wouldn't happen in real life.
Right, okay.
The idea is you can't just turn every identifier into an R value because it might be needed later.
Okay, oh, I see what you're saying, yes.
In the same expression, it might be needed a second time
and you have no way of knowing that.
So you can't just go willy-nilly
turning things into R values.
Right.
But specifically in the case of return X semicolon, right?
Right.
So a named value.
Yeah, we have an intuition that serves us well most of the time
that x is actually going to be either moved from or not exist at all
because it's been copy-aligned in that specific case.
And so all I'm trying to do is patch the holes in that intuition
because there are cases where you use that intuition and it actually doesn't work.
You actually get a copy.
I want those to go away.
I don't necessarily want to create new cases where you have to learn a new intuition that, oh, now I see it's going to get moved in this case.
You want to take the intuition you already have about it being moved and just make sure that actually happens.
That sounds fun. There's also a related case that David Stone has a proposal that I think is going to core
in the next meeting that deals with return x, where x is actually a parameter or a local
variable of rvalue reference type. So if I take an rvalue reference parameter,
you know, string ref ref x,
and then I say return x,
that that will actually move out of x.
This to me is actually scarier than what I'm going to say.
No, that sounds dangerous,
because you may never,
just the fact that you have an rvalue reference
does not mean that you ever wanted to
or intended to move.
I mean, that's something that might be moved.
It is not something that is going to be moved.
Well, he's making it something
that is going to be moved.
I mean, you are returning it.
So you know you are...
You're going to be either getting a copy of the value
or if the return type of the function
is like string ref ref and x is like string ref ref, and x is a
string ref ref, it makes sense that I should be able to return x. Yeah, it's, I think, less
intuitively obvious. Like, it feels a little bit unsafe to me, but I believe that the Evolution
Working Group thought, okay, sure, let's do it. And it would make certain idioms a little bit easier.
Things where you return decltype auto.
Right.
Wait, does that work?
Well, no, that would actually change the meaning
of return decltype auto in some cases
from what it currently has.
That could be a breaking change.
From returning an L value to an R value, yes.
Yeah.
Well.
But that one is progressing,
and so I have hope that my more conservative one,
which, you know, he's proposing this one thing about R value references,
I'm proposing this other thing about regular old values,
and I'm hoping that they will sort of progress together
and we'll end up with
both well hopefully they are both fully considered their impacts on each other if they both get
through yes my paper actually has uh two wordings it has a wording against the current draft and
also a proposed wording that's a diff against david's uh proposal um that says if his gets in, here's what we then
remove even more code,
remove even more text from that paragraph
to enable
things like conversion
operators and by-value
parameters.
So
I'm hopeful for that one.
I wanted to interrupt this
discussion for just a moment to bring you a word from our sponsors.
Backtrace is a debugging platform that improves software quality, reliability, and support
by bringing deep introspection and automation throughout the software error lifecycle.
Spend less time debugging and reduce your mean time to resolution
by using the first and only platform to combine symbolic debugging, error aggregation, and state analysis.
At the time of error, Bactres jumps into action, capturing detailed dumps of application and
environmental state. Bactres then performs automated analysis on process memory and
executable code to classify errors and highlight important signals such as heap corruption,
malware, and much more. This data is aggregated and archived in a centralized object store,
providing your team a single system to investigate errors across your environments.
Join industry leaders like Fastly, Message Systems, and AppNexus that use Backtrace to modernize their debugging infrastructure.
It's free to try, minutes to set up, fully featured with no commitment necessary.
Check them out at backtrace.io.cppcast.
And then you have a third paper trivially relocatable right
trivially relocatable yes um so uh man where to start with this hey what one of you guys should
have you have you can you summarize this paper and then i can just i can just correct you
yeah i haven't actually read it yet, I don't think.
But I've heard mentions of it for a while.
Yeah.
So yeah, this is an idea that's been around in one form or another for a very long time.
Most recently in history, Pablo Halpern, around 2014, I think, had a series of papers called Destructive Move.
And this is similar, but I think more conservative and more performance-oriented than Pablo's Destructive Move.
The idea here, think about vector resize, or vector reserve, or pushback, or any of these things that
reallocates the vector. Let's say I have a vector of int, and I reallocate that vector. I make a
new memory buffer, and I just take the ints from the old buffer and copy them over into the new
buffer, and then I deallocate the old buffer. And if I were dealing
with strings, that wouldn't be a correct
implementation, because I said copy, and I
didn't say anything about destroying the old ones. But in case of
int, I can actually just literally memcopy
the data from
the one buffer to the other, and then I can just drop the old
buffer on the floor by deallocating it. I don't need
to call destructors, because it's trivially
copyable.
Just for the sake of our listeners, currently standard containers take advantage of this with the is trivially copyable
trait yes okay um but if i had a and this would work also if i had like int star int star is
trivially copyable right right but as soon as i give it some raii features um as soon as i give
it a destructor move constructor if I have unique putter event
and I have a vector of unique
putter event and I
reallocate it,
suddenly I don't use memcopy anymore.
Now what I'm going to do is I'm
going to use the move constructor of unique
putter to move construct
each unique putter from the
old buffer to the new buffer.
And then once I'm done moving them,
then I can go back and call the destructor
on every one of those unique putters in the old buffer,
which, of course, it's nulled out at this point,
so the destructor doesn't do anything, but I still call it.
And even if it gets inlined,
we can see that compilers are not perfect at this.
You might think, oh, well, the destructor is obviously a no-op.
It should just obviously not do anything.
But in practice, no, compilers,
if there's a loop with a function call in it,
they're going to do something that's not nothing.
Probably.
I mean, you can go on Compiler Explorer,
and the paper actually has links to several Compiler Explorer.
Well, I didn't mean to be terribly contradictory.
It's just I have a bunch of examples in my training material,
and I've noticed that every six months when I go to teach the same class again,
I'm like, oh, well, now Clang's optimizer is actually doing this,
so it's a bad example now.
So, yeah.
Yeah, but you don't usually have to tweak it that much,
I would think, to make it back into the bad category.
Yeah, it depends.
So vector of unique putter, reallocating.
But if you think about it, you could actually use memcpy to reallocate the vector's buffer of unique putters, right? If I just used memcopy and copied the
pointer values from the old buffer to the new buffer, and then I deallocated the old buffer.
Without calling the destructors. Without calling the destructors.
Which currently is undefined behavior to free an object without calling its destructor,
if it's not trivially destructible. I don't think that's technically true.
I mean, it's certainly not something that you would think is a good practice.
I believe that's true because it comes up in the case of non-virtual base class destructor is technically undefined behavior.
The thing about non-virtual base class destructors is if you
delete through the pointer to base at that point,
that's not only undefined behavior,
but it's actually wrong, because you're going
to be, the delete operator
is going to be handing some memory back
to the, you know, to malloc and
free, or wherever your heap is,
and it's going to be handing back the size of the
base object, not the size of the derived
object, and it's actually going
to corrupt your heap by doing that.
Okay.
So I don't even know if that's undefined behavior, but it's certainly, you know, it's got to
crash, right?
So there's a reason that that should be undefined behavior or something.
Right.
In the case of just handing back the memory, as long as you hand back the right amount
of memory without calling the destructor, I mean, maybe from C++'s point of view, the
object is still in some sense
there. I don't really know.
Maybe it's undefined behavior. But anyway,
this is certainly the thing that's
really undefined behavior here would be
I'm doing the memcpy into this
uninitialized buffer,
a new buffer, right? I'm memcopying
a bunch of data in, and then I'm just saying, I'm going to
assume these are unique putters. I'm going
to treat them like unique putters, even though I never
constructed a unique putter there. I just memcopied
some stuff into a
newly allocated buffer. So
yes, this is totally undefined behavior.
And so
library vendors today
don't do it. They're very
scared to do this optimization,
which means
if you have a vector of unique putters and
then you resize it, it's going to be slower than if you used a library implementation
that wasn't scared to do this optimization, such as EASTL, BSL, Folly, all do this optimization.
In fact, Folly's FB vector, that's Facebook Folly, Folly's FBVector actually
enforces
in the docs for FBVector, it says
your type must be trivially relocatable.
But since that's not a
trait that currently exists, how
do they enforce that?
How do they know whether it's something that can be done?
They enforce it by
if you get it wrong,
then you have a bug and your memory probably gets corrupted.
Okay, so there's no real enforcement.
Yeah, they have no way of verifying that a type is or is not trivially relocatable.
And for example, by the way, unique putter is trivially relocatable, shared putter is trivially relocatable, string is generally trivially relocatable. Shared ptr is trivially relocatable. String is generally trivially
relocatable. But there are cases, function is one that actually differs between libc++ and
libstdc++. Std function, a common way of implementing the small object optimization,
where you take the original object that you're wrapping in the std function,
and normally that would be heap allocated, but you can also put it inside the body of the std
function object itself. And when you do that, the internal pointer that the std function object
holds to the controlled object, that pointer can point into the body of the std function itself.
And then when you move the std function, you have to update that pointer to point into the body of the std function itself. And then when you move the std function,
you have to update that pointer to point to the buffer
inside the new destination object.
And so you can't do that with memcpy.
Okay.
So I forget which is which,
but I think libc++ does that with the internal buffer
and therefore is not trivially relocatable,
whereas GNU's libstdc++
std function actually is trivially relocatable.
Okay.
I think that's the right way around.
The paper says for sure.
And so, yeah, you can have these cases
where even a standard type that exists
on two different platforms
but actually has different behavior in this respect.
And so, you know, if, for example, you're using folly FB vector exists uh on two different platforms but actually has different behavior in this respect and so you
know if for example you're using folly fb vector and you have a vector of std function uh that
could work totally fine until you change your uh you know your platform and you go to apple and
suddenly it doesn't work anymore it worked fine on linux it doesn't work on Mac OS, right? Right. Because there's no way to static assert this property.
And so what my paper is proposing is a family of type traits.
You know, std is trivially relocatable, is trivially relocatable v, that kind of thing.
That you can ask, hey, compiler, do you know that this type is trivially
relocatable? And then that would be true for things like unique putter and shared putter and
string and so on and function when it is and not when it isn't. And so you could actually static
assert it or switch your behavior, depending on whether it was trivially relocatable or not.
It's, it sounds like something that the compiler could not automatically determine,
like just based on your std function example, like how does that work? So the compiler can determine it in a
lot of cases. If you just have an aggregate or something where the move constructor and the
destructor are defaulted, then you just look at the members and you look at the bases and you
propagate the information in the logical way.
And the paper has core language wording for how that works.
But it's obvious.
It's just the same as trivially copyable.
So in a lot of cases, the compiler can tell.
The problem is, what happens if I have something that does have a user-provided move constructor and or destructor?
In those cases, the compiler has to conservatively assume that the thing is not trivially relocatable.
Okay.
So then we need an opt-in mechanism for the programmer,
or the library vendor, whoever it is, to say,
hey, compiler, I know you're going to assume
that this is not trivially relocatable,
but I promise that I have done the work
and made the proof or whatever
that says that my move constructor
and my destructor are
meshed together in the proper
way such that I preserve
trivially relocatability.
So we need a way to warrant to the compiler
that you've done that work.
And in my
proposal, I propose this be done
through an attribute.
You're supposed to gasp at this point. Nah, I propose this be done through an attribute. Okay.
You're supposed to gasp at this point.
Nah, I don't care.
Attributes are everywhere now, so...
Yeah, that's what I feel.
Sure, an attribute.
So you put the attribute on the type,
and, you know, attribute trivially relocatable,
and that tells the compiler
that it should ignore its normal conservative estimate
and just assume that your type is trivially relocatable because you said that it was.
Okay. I'm not going to gasp. Sounds like an idea.
And I've got examples, both in the paper and in a fork of libc++,
that show how to do this conditionally.
Because you have to, for example, for std vector, a fork of libc++ that show how to do this conditionally.
For example, for std vector, std vector is normally
trivially relocatable as well
because it just has a couple of pointers in it.
But those pointers actually
aren't necessarily pointers.
That's the allocator's pointer type
and it could be some wacky
thing or the allocator itself might be some
wacky thing.
So you have to do some metaprogramming so if you use like a stack-based allocator or something yeah yeah yeah well even that's probably fine because it's just the allocator is just a
pointer to a heap i would talk about that too you should all go watch that right um an allocator is
a handle to a heap but that handle type itself could be something wacky. Live.
Yeah.
So you have to do some metaprogramming to say, you know, if my allocator's pointer type and my allocator are trivially relocatable,
then I am trivially relocatable.
Otherwise, I am not.
But that metaprogramming is fairly mechanical.
It's something that certainly
library vendors would be used to doing.
And we're looking at
ways, I think that's the
biggest area of
possible evolution in this
paper is
maybe the attribute should take a Boolean
parameter that could just be true or false
and you can put all your metaprogramming
right in the argument to the parameter and not have to mess around with like, you know, conditionally relocatable base classes and things.
Are there any conditional attributes currently?
There are no standard attributes that take this conditional parameter.
But there are several that have been non-standard attributes that have been done by Clang,
and I think also by GCC.
There's a non-standard enable-if attribute that works just like std enable-if,
but is faster.
And Clang also has diagnose-if,
which is used for things about versioning in the Apple headers.
And there are
attributes that take a parameter
also. Things about alignment.
I think the assume align that just
got in.
I think that's done with an attribute and I think it takes
a parameter. Maybe don't quote me on that one.
Contracts will have
that kind of thing all over the place.
Contracts? Well, pet peeve of mine, contracts
are... They're officially attributes, but they're not we'll have that kind of thing all over the place. Contracts. Well, pet peeve of mine contracts are there.
They're officially attributes,
but they're not because they don't follow the attribute grammar.
Oh,
that's,
I didn't realize that.
Um,
they like half follow it,
right?
They've got the,
the,
the square brackets around them,
but then instead of having parentheses for the argument,
they have a colon,
right?
Expects colon and then an expression,
right? So that's not
really following the attribute
grammar. They're like a separate
thing that is called
attribute in the standard, but it's not.
Compilers are not
going to call them attributes.
The paper standard is going to call them attributes,
but it's going to be a separate kind of attribute.
I don't think contracts
are ready. I don't think contracts are ready.
I don't think a lot of things are ready. Well, still some time to iron out all that stuff,
right? Hopefully. Yeah. I wish that the standard would go back to an eight-year release cycle.
Really? I mean, it was before my time, but C++11 ended up being pretty awesome, right?
Yeah, but that was completely accident. They wanted to release it much sooner than that yeah well i think we should go back to having accidents then the problem now
is we've been sticking to the three-year schedule and every three years it comes out and people go
what we voted for that i remember waiting for c++ ox to come out for like four years like okay
what's going to happen with this so i'm not sad that it's moved
to a faster schedule well i think the i mean one of the reasons i guess that c++ 11 looks so awesome
is because c++ 03 was so bad um right um you know because otherwise what i would say to that is you
know you were waiting and waiting and waiting but at in the meantime, you could just use C++ 03 and everyone knew it.
You could actually have people who graduated college using C++ 03,
and they could go get a job using C++ 03.
That was amazing.
These days, you can't even get a four-year degree without having a couple of releases of C++ in the middle of it.
That's what college is about, is learning
how to learn new things.
Yeah, but you have
to learn how to learn them first.
It's just throwing you right in the deep end, saying, no, you have to go out
and learn this thing.
Whereas if we went back to an accidental
schedule where people said,
people stop calling it C++20, I try to call it
C++2A.
That's my pet.
Then you must hate all my most recent uh c++ weekly episodes because i'm just calling it c++ 20
all over the place i'm like everyone does but i'm i'm really trying to to stick to the like
you know the old you know 0x and then there there was uh you know 1y and 1z and now everyone just
like oh yeah it's, it's just 20.
We've gotten used to saying, oh, well, it's going to come out in three years.
But we've also gotten used to saying, like, it's going to come out in 20,
and maybe it'll have this feature, and maybe it won't.
And I hope we have time to figure out all of the kinks.
We've got time.
We've got a whole year before it's going to be frozen.
That's plenty of time to figure out all the problems with it. But historically, I think it
has not been. I think we have problems with things like structured binding. We have problems with the
constructor template argument deduction, problems with half of PMR apparently getting left out by accident.
And I think if we went back to making mistakes and slipping,
and saying, oh wait, it's actually not cooked yet,
and then being real apologetic and everyone getting mad about it,
but producing the next C++11 in the process.
And in the meantime, people could graduate college using C++17
and get a job using C++17
and actually, you know, catch up.
You know, that would...
I feel like I want that. I know it's not
going to happen, right?
I will say
all of the issues
that we have with initializer list
happened with C++11,
and that was after all that extra time of baking.
So that might not be the end solution.
You know, that is a fair point.
There's plenty of stuff that was in 11
that was problematic as well.
I mean, error code.
That's fair.
So anyhow... Yeah, I mean, I, I think the way that we ended up dealing with that is just
basically people ignored a lot of 11, you know, it's hard with the initializer listing
in particular, but there's a lot of pieces of 11 that people just ended up, uh, not caring
about.
Um, and I think we're seeing that also
with things that come in in 17
and people go like,
oh, well, I just won't use that piece.
Which is fine.
That is the way it's always been.
But I just don't want the number of pieces
people aren't using
to outweigh the number of new pieces
that people are using.
Otherwise, what's the point of adding things?
Right.
I was going to say
we're running out of time, but is there anything
you want to plug or mention
before we let you go today, Arthur?
Sure.
Not a whole lot.
You didn't get a chance to talk about your book.
You wrote a book about C++17
STL, right? I did buy a book.
I didn't write a book. People should buy it.
We also didn't mention that you
publish an article about three times a day
on your blog.
Yeah.
I think there was actually one day
where I did do three in a single day,
but that is uncommon.
It's getting less common now, actually.
I started it because
I just
had so much
stuff that I wanted to
spew out into the world and
it seemed like that was the right
place to do it so I was very prolific early
and now it's slowing down and I'm getting
more conscientious about
having to actually think about things before I
say them a little bit
makes it take a lot longer
I'm working on a post right now about covariance and contravariance
and
sort of put it down for a couple of days
because I was like
this makes no sense and it's disorganized.
So in the old days
I would just put it right up.
But yeah, I also have a book
Mastering the C++17 STL. If you like
my blog, you'll like the book.
If you want to learn C++ from the ground up,
don't buy that book.
Go buy a tour of C++ or something instead.
But it's sort of eclectic.
It's organized like a tutorial,
going through each chapter of
here's something the standard library has.
It's got a chapter on algebraic data types. It's got a chapter on the new standard library has. It's got a chapter on algebraic data types.
It's got a chapter on the new file system stuff.
It's got a chapter on PMR.
But the content is essentially
stuff that I feel is interesting to know about.
And I think there's stuff there for,
especially for people who think
that they know the language
or at least are a C++14 expert,
but are maybe a little bit shaky on 17,
then I think it would be a great read.
And after I wrote it,
I realized there is no chapter on string.
I just left out strings and string view entirely.
I don't even feel bad about it, because I didn't have
that much interesting to say about them at the time.
If I ever do a second edition, I should probably
put in a chapter on strings.
So I have a book, I have a blog.
I am giving a talk at the
New York C++
meetup tomorrow night.
So it's probably not even going to be up by then.
But yeah, another use for that time machine.
They can go back and they can see your talk about initializer list,
and then they can go see my talk about concepts in New York.
And I'm hoping the New York meetup picks up.
I was the organizer of the San York meetup picks up.
I was the organizer of the San Francisco meetup
when I was out there, and then I moved
to New York in
November or December
just this past year, so I haven't been out here very long.
And
I'm looking to get the New York meetup
started up,
doing regular, at least monthly things. And so if
there are viewers out there, listeners out there in Radioland, in the New York area,
I know we have at least some. Join the Slack channel. Yeah, we do.
Where approximately, I mean, New York's big. Manhattan. I mean, where is everything, right? Okay.
Yeah. I mean, I actually live up in Yonkers,
which is unfortunate for not a whole lot of C++ people this far north. But the meetup has been meeting at the MongoDB headquarters in Manhattan.
Okay.
Okay.
And, yeah.
Cool.
Okay.
Well, it's been great having you on the show today, Arthur.
Yeah.
Well, thank you for having me.
Thank you for letting me talk and, yeah, talk at you.
Thanks for coming on.
Yeah.
Thanks so much for listening in as we chat about C++.
We'd love to hear what you think of the podcast.
Please let us know if we're discussing the stuff you're interested in,
or if you have a suggestion for a topic, we'd love to hear about that too.
You can email all your thoughts to feedback at cppcast.com.
We'd also appreciate if you can like CppCast on Facebook and follow CppCast on Twitter.
You can also follow me at Rob W. Irving and Jason at Lefticus on Twitter.
We'd also like to thank all our patrons who help support the show through Patreon.
If you'd like to support us on Patreon, you can do so at patreon.com slash cppcast.
And of course, you can find all that info and the show notes on the podcast website at cppcast.com. Theme music for this episode was provided by podcastthemes.com.