CppCast - Trivially Relocatable

Episode Date: January 10, 2019

Rob 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)
Starting point is 00:00:00 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.
Starting point is 00:00:47 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
Starting point is 00:01:47 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.
Starting point is 00:02:13 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
Starting point is 00:02:33 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
Starting point is 00:02:49 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.
Starting point is 00:03:05 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.
Starting point is 00:03:29 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,
Starting point is 00:03:47 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,
Starting point is 00:04:08 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.
Starting point is 00:04:28 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.
Starting point is 00:04:47 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,
Starting point is 00:05:07 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.
Starting point is 00:05:31 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
Starting point is 00:05:48 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.
Starting point is 00:06:04 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
Starting point is 00:06:40 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
Starting point is 00:07:27 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
Starting point is 00:08:13 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,
Starting point is 00:08:51 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.
Starting point is 00:09:15 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
Starting point is 00:09:56 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.
Starting point is 00:10:27 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
Starting point is 00:10:52 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.
Starting point is 00:11:17 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,
Starting point is 00:11:45 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
Starting point is 00:12:06 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
Starting point is 00:12:50 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.
Starting point is 00:13:20 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...
Starting point is 00:13:39 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,
Starting point is 00:13:56 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
Starting point is 00:14:29 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
Starting point is 00:14:55 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.
Starting point is 00:15:17 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
Starting point is 00:15:42 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.
Starting point is 00:16:22 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
Starting point is 00:16:48 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
Starting point is 00:17:03 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
Starting point is 00:17:48 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.
Starting point is 00:18:05 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
Starting point is 00:18:37 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
Starting point is 00:19:09 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
Starting point is 00:19:25 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
Starting point is 00:19:58 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
Starting point is 00:20:27 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.
Starting point is 00:20:54 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...
Starting point is 00:21:16 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
Starting point is 00:21:43 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.
Starting point is 00:22:18 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
Starting point is 00:22:34 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
Starting point is 00:22:52 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.
Starting point is 00:23:06 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,
Starting point is 00:23:37 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?
Starting point is 00:23:57 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
Starting point is 00:24:14 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.
Starting point is 00:24:30 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?
Starting point is 00:24:55 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
Starting point is 00:25:30 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
Starting point is 00:25:51 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
Starting point is 00:26:07 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?
Starting point is 00:26:41 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
Starting point is 00:27:17 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,
Starting point is 00:28:11 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
Starting point is 00:28:38 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.
Starting point is 00:29:04 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,
Starting point is 00:29:24 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.
Starting point is 00:29:54 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.
Starting point is 00:30:19 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.
Starting point is 00:31:08 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
Starting point is 00:31:53 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,
Starting point is 00:32:18 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.
Starting point is 00:32:47 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?
Starting point is 00:33:04 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.
Starting point is 00:33:28 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,
Starting point is 00:34:12 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.
Starting point is 00:34:29 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
Starting point is 00:34:47 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
Starting point is 00:35:19 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,
Starting point is 00:35:38 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
Starting point is 00:36:09 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.
Starting point is 00:36:27 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,
Starting point is 00:37:03 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.
Starting point is 00:37:46 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
Starting point is 00:38:41 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
Starting point is 00:38:59 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
Starting point is 00:39:29 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,
Starting point is 00:39:46 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.
Starting point is 00:40:08 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,
Starting point is 00:40:33 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.
Starting point is 00:40:55 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
Starting point is 00:41:42 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
Starting point is 00:42:00 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.
Starting point is 00:42:17 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
Starting point is 00:42:36 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
Starting point is 00:42:51 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
Starting point is 00:43:11 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?
Starting point is 00:43:37 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
Starting point is 00:44:13 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.
Starting point is 00:44:52 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.
Starting point is 00:45:12 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
Starting point is 00:45:31 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.
Starting point is 00:46:20 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.
Starting point is 00:46:55 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,
Starting point is 00:47:21 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
Starting point is 00:47:38 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...
Starting point is 00:47:53 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.
Starting point is 00:48:16 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.
Starting point is 00:48:38 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.
Starting point is 00:49:09 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
Starting point is 00:49:31 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?
Starting point is 00:49:53 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
Starting point is 00:50:25 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.
Starting point is 00:50:42 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,
Starting point is 00:50:53 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?
Starting point is 00:51:02 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.
Starting point is 00:51:17 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
Starting point is 00:51:51 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.
Starting point is 00:52:35 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.
Starting point is 00:52:55 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
Starting point is 00:53:23 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
Starting point is 00:53:48 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
Starting point is 00:54:30 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,
Starting point is 00:54:47 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
Starting point is 00:55:10 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.
Starting point is 00:55:32 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
Starting point is 00:55:46 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.
Starting point is 00:56:02 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.
Starting point is 00:56:18 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
Starting point is 00:56:33 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
Starting point is 00:56:49 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,
Starting point is 00:57:07 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.
Starting point is 00:57:28 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,
Starting point is 00:57:49 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.
Starting point is 00:58:17 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.
Starting point is 00:58:41 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
Starting point is 00:58:58 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.
Starting point is 00:59:45 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.
Starting point is 00:59:57 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.
Starting point is 01:00:20 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.

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.