No video

C++ Weekly - Ep 421 - You're Using optional, variant, pair, tuple, any, and expected Wrong!

  Рет қаралды 28,857

C++ Weekly With Jason Turner

C++ Weekly With Jason Turner

Күн бұрын

Пікірлер: 141
@gregorssamsa
@gregorssamsa 4 ай бұрын
Should be fixed in C++29
@oriyadid
@oriyadid 2 ай бұрын
Surely that won't be delayed to C++32
@Arwahanoth
@Arwahanoth Ай бұрын
@@oriyadid for backward compatibility it will probably not be fixed. but hoppefully you will have a new Wnrvo coming soon.
@sqlexp
@sqlexp Ай бұрын
It requires something like data-member RVO, where the Lifetime object is constructed in place at the Lifetime member of std::optional/std::expected, but those types will need to provide some standard declaration (maybe a concept) to mark the designated data member and some special constructor that assumes the designated data member is initialized when the constructor is called. That data member needs to be destroyed last if an exception is thrown during data member initialization in that constructor.
@sqlexp
@sqlexp Ай бұрын
Some additional support will be needed if the data member is in a union.
@N....
@N.... 5 ай бұрын
6:19 you can just write `std::in_place`, no need to write the extra `_t{}`
@josephnyu
@josephnyu 5 ай бұрын
I think Jason missed a point, for functions returning expected it is very likely to have branching, and in that case RVO will use move constructor most of the time anyway. The same can be said for optional (indeed if your code always return a Lifetime then the return type should be Lieftime and not optional)
@LesleyLai
@LesleyLai 5 ай бұрын
This makes me appreciate Rust's "move by default." While annoying in other areas, that semantics means the compiler can optimize this kind of code well and we don't need to think about this issue
@kuhluhOG
@kuhluhOG 5 ай бұрын
with the difference that the value gets moved (e.g. 10:05)
@niklkelbon3662
@niklkelbon3662 5 ай бұрын
)) rust has no RVO and copy elision, values will be moved (memcpy) every time. So, C++ better here
@joestevenson5568
@joestevenson5568 5 ай бұрын
​@@niklkelbon3662C++ is only better here is written perfectly. Rust - as usual - has vastly superior default behav
@TRex266
@TRex266 5 ай бұрын
​@@niklkelbon3662right, but for something like a string memcpy is not really an issue..? You only copy the pointer, not the buffer
@tiagocerqueira9459
@tiagocerqueira9459 5 ай бұрын
​@@niklkelbon3662 llvm does RVO, but the language and Mir can't guarantee that
@axelBr1
@axelBr1 5 ай бұрын
Self taught C++ in early 2000s, and have started to use it again, after work took me away from it. Have recently heard of RVO and have just started incorporating std::optional into a project I'm working on, as being able to say that there is no value to return is really helpful. And then I saw this.
@Evan490BC
@Evan490BC 5 ай бұрын
Run away while you can!
@DominicDW8
@DominicDW8 5 ай бұрын
Well, don't be too sad. It's oftentimes worth using the "inefficient" way to get more readable code. The "issue" shown in the video is certainly quite interesting, but also quite certainly not a deal breaker for performance in the vast majority of use cases.
@DamianReloaded
@DamianReloaded 5 ай бұрын
This seems like something the compiler could optimize for.
@japedr
@japedr 5 ай бұрын
Except when it cannot... as shown in the video. Any class without a trivial destructor is affected by this, and that includes all classes with a vector or a string as a member.
@Yxcell
@Yxcell 4 ай бұрын
@@japedr But isn't the reason why Jason's code with the extra constructor/destructor calls couldn't be optimized out was due to the fact that the all called print() ? When I checked out the Compiler Explorer instance that Jason linked in the GitHub page for this episode, I removed the body of the print() function and the resulting assembly became that of a barebones program. I'm kind of a noob at C++ so I might be missing something here.
@MantasXVIII
@MantasXVIII 4 ай бұрын
​@@japedryeah but haven't you heard? The compiler knows better than you. Premature optimization is the root of all evil.... And other such nonsense from people who've worked on a serious project
@AtomicAndi
@AtomicAndi 4 ай бұрын
seems like it optimizes (prematurely) for an empty optional!?
@Muzzleflash1990
@Muzzleflash1990 4 ай бұрын
It does optimize it all. But it ofc not remove the observable side effect of printing.
@VoluneAneline
@VoluneAneline 5 ай бұрын
I suspect a lot of people will write "return std::unexpected{"oh no!"};" and that will prevent RVO anyway (at least when I tried). I guess we will (again?) rely on tooling to fix these issues. If the compiler cannot optimize in the first place for most cases.
@gwendolynhunt2493
@gwendolynhunt2493 4 ай бұрын
Thanks Jason, now I have a couple hundred APIs in several libs I need to revisit. Really, an excellent YT. You do good work.
@mjKlaim
@mjKlaim 5 ай бұрын
Good to know, thanks for pointing this!
@dookshi
@dookshi 4 ай бұрын
Haha, I regret no episode of yours! In fact, you did such a good job explaining RVO so far that I did not find anything you did not already cover implicitly. You just made it explicit now. Excellent series!
@MatthewWalker0
@MatthewWalker0 4 ай бұрын
I have thought about this a few times. And, every time I imagined what the "fewer moves" code would look look, it seemed like a premature optimization making the code less readable; it looked more like C89 code with the variables and return value declared at the beginning of the blocks. Much cleaner to just put a couple `if (bad) return std::nullopt` around.
@erikgrundy
@erikgrundy 4 ай бұрын
I know C++, kind of, but haven't actually used it in any real applications, so I don't really experience the issues I sometimes see talked about, like this one. So for those more experienced than me: how often do these sorts of things end up mattering? A lot of online C++ content loves to talk about small ways of squeezing a little bit more performance out of your code. These sorts of micro-optimisations don't strike me as the thing that will make the difference between your code being acceptably fast or not. E.g. the specific problem presented in this video. I would think that the majority of the classes you write in an application don't have anything fancy going on in their various constructors, assignment operators, and destructors. So I wouldn't think that this would make an enormous difference. Would it make your application faster? Probably. But I would think that the things to target when it comes to optimisation would be less granular. I'm happy to be wrong, so feel free to challenge my assumptions. I'm genuinely looking for an answer for why the C++ community seems focused on optimisation to such a degree.
@stevenfranzen2161
@stevenfranzen2161 4 ай бұрын
I think this is just inherent to C++ as a language where you can almost always avoid paying costs like execution time and/or memory usage, if they aren't strictly needed. You're entirely right that this kind of thing will not typically matter to a specific application, but on the other hand, as a library writer you don't want to force unnecessary pessimisations on your users. And as a language designer you want to make it easy for library writers and other users to avoid those. I think that's at the core of Jason's criticism here. Although I don' t teach programming, the only thing I would ever teach about optimisation is that you just have to profile your code if performance is a concern. Especially with C++, it's almost impossible to predict what an optimising compiler will produce, so it's better to observe general guidelines for readable, maintainable code and avoid premature optimisation.
@JanFlunher
@JanFlunher 4 ай бұрын
Definitely not as good as some people commenting under these videos, but having used C++ in personal projects and work...I don't think you think about the bigger picture. The underlying object could represent anything and be called from anywhere. Once this function is called in a loop in some hot path, the performance impact is non-negligible. I remember refactoring some code and overlooking that I passed a copy of a vector to some lambda by mistake; or something similar. Rookie mistake. Didn't realise it until I benchmarked and found out that the code is like 5x slower. Might sound like a lot, but if it takes 50ms instead of 10ms, you probably won't notice until you actually benchmark it. Returning a copy from optional/variant/... like shown in the video could have the same impact. Moving instead of RVO might not be that big of a problem, but still - it's unnecessary. I'd say that the feeling that the C/C++ community is more focused on optimisation is because that's just the kind of stuff that's mostly written in C/C++. There isn't much of a reason to use it for other stuff; or rather there are better languages/tools (that might just be a wrapper over some C/C++ libraries and therefore the "hot paths" being performant anyway - so why make your life difficult?).
@erikgrundy
@erikgrundy 4 ай бұрын
@@JanFlunher but you only discovered your error when benchmarking, which i think is the right time. i don't dispute that this *could* have a performance problem, and indeed i think it's not unreasonable to use the faster version in all cases - it's not notably less readable. my observation is more generally about the c++ community, who (in my observation) will often claim that you should always prefer x to y in all cases, without considering that y may be more maintainable, readable, etc. c++ is used in lots of high performance scenarios. but it's also used in places where code readability and correct abstractions are important. this was one of the core principles of c++. and yet i see people reject an idea that improves readability solely on the idea that it *might* worsen performance. you can only know that by testing it, rather than assuming that it will make your code unbearably slow.
@JanFlunher
@JanFlunher 4 ай бұрын
​@@erikgrundy Yes, I discovered it, but I don't always benchmark all of my code. And in a big code base, that might be riddled with stuff like this, it will definitely become a problem for not-so-obvious reasons. Small performance issues become big ones once they come in herds. Can't speak for the community as a whole. But I personally like to always write the most performant code in most cases, because it's a good training for when it actually matters...and saves a lot of headaches later. Though the "most performant" is highly subjective obviously. Adding an explicit "std::optional(...)" isn't a deal breaker for me here. Doing everything with template meta-programming is a big nope. I'm still a fan of readable code. The thing in this case is that not only it *might* worsen the performance, but it always *will* and it's not very obvious. If it's negligible or not, depends.
@cppweekly
@cppweekly 4 ай бұрын
I don't consider this a micro optimization, I consider it a matter of understanding what your tools are doing. This is the kind of thing that, once I understood it, I got about a 100x performance improvement in my scripting engine. It was a kind of "death by 1000 cuts" In my experience this is where most performance is lost in a C++ program, but people don't think about it and instead do things like inline assembly to try to get an extra bit of performance out. kzfaq.info/get/bejne/orSedaipqdWyg4U.html
@Psy45Kai
@Psy45Kai 5 ай бұрын
I think there is a problem with the test setup here: The Lifetime class always have an IO side effect. These cannot be optimized away by the compiler properly! But classes following the rule of zero might not be affected ☝️ I would like to see a follow-up with optional and optional analysing the asm.
@Muzzleflash1990
@Muzzleflash1990 5 ай бұрын
You have to be careful to distinguish the guaranteed "copy elision" conditions with general optimization. In fact, if the guaranteed copy elision rules apply then the side effect MUST NOT happen due to the delayed materialization. Suppose you did: Lifetime x = f() where f() function returns a Lifetime (not inside optional or anything) simply by: return Lifetime{42}; then there MUST only be single construction since C++17. The problem is none of these guaranteed copy elision rules apply here. The constructor for optional or the others, take a reference (&&) to the contained type forcing the materialization of an extra Lifetime. So in terms of language semantics it must create the object. You are then right, that under the as-if rule the compiler could automate the copy away, if it did not have a side effect.
@aniketbisht2823
@aniketbisht2823 5 ай бұрын
This is really unfortunate. I think you should discuss this with Arthur O Dwyer. He has proposed many papers on topic of returning objects (and implicit moves) and has also given talks on this subject. This seems like a missed optimization opportunity as far as core language is concerned. This case is very similar to the C++17 guaranteed copy-elision. We can generalized that approach to elide copying any object/value that is used to construct the returned object (given the converting constructor of the returned type itself is not explicit).
@jirihavel9766
@jirihavel9766 4 ай бұрын
It's not just missed optimization. All these prints are observable side effects that optimizer can't remove. We may need one of those : - print that can be removed by the optimizer (must be explicitly allowed by the standard) - removing any side effects from copy constructors (i.e. copy constructor is only allowed to do copying) This however leads deep into the "undefined behavior" territory. - explicitly allow copy ellision or return value optimization in these situations. All are decisions in the standard. Compiler authors aren't allowed to do this on their own.
@Muzzleflash1990
@Muzzleflash1990 4 ай бұрын
To the people thinking this is about RVO (copy elision): it is not. And by the way RVO works fine (which is why you don't see extra outputs from an internal copy of Lifetime when the optional is copied out as a return value: because it is not). The problem is when you have a Lifetime object but what you really want to return is an Optional which implicitly causes the Optional constructor to be called with a Lifetime. As this point (language-wise) the Lifetime must be materialized because the parameter is a glvalue. So Lifetime{42} is materialized as the parameter. Then the inner Lifetime is move constructed from that. The issue here is nothing to do with RVO, but with calling functions (constructors) to make a class B by passing an A and expecting the construction of A to be elided; which is won't. The resulting Optional is perfectly NVRO'ed (which is actually an optional optimization) in the first example; or (unnamed) RVOed out in the remaining cases. And RVO has nothing to do with the constructor/destructor being trivial or not (if elided those copies never existed at all!). For example: godbolt.org/z/fMKzxEbj6 . But can't the compiler optimize it away anyway? In many cases: probably sure. What it can't optimize away is the observable side effect of outputting.
@sirhenrystalwart8303
@sirhenrystalwart8303 4 ай бұрын
When is it not allowed to elide the side effect of printing? RVO works fine in all these cases if your remove the optional.
@Muzzleflash1990
@Muzzleflash1990 4 ай бұрын
@@sirhenrystalwart8303Basically, eliding is allowed (and required) when returning unnamed temporaries of the same type as the return value. If you remove the optional then RVO triggers since you are just returning the Lifetime (prvalue) you construct: no intermediate is constructed; only the final value. As the R in RVO hints it works for Return values, but following has nothing to with RVO. The problem is that binding references to temporaries force the construction of the referred to object. When you return an Optional you have to go through the constructor of optional (any function really) that has a named parameter compatible with the inner value. These parameters are references that bind to the prvalue, and by the spec, then the value must be materialized, and thus the printing must be shown.
@PaulMetalhero
@PaulMetalhero 4 ай бұрын
+1 for the cppreference dark theme!
@VictorYarema
@VictorYarema Ай бұрын
Awesome episode. I don't regret watching it. Now I can better remember about this specific pitfall. The worst emotion now is a frustration caused by so called "standard" which was supposed to make everyone's life easier instead of making really bad things harder to spot.
@FixedTypo
@FixedTypo 5 ай бұрын
We often face the situation that our objects are returned by some sort of factory function before being placed into the optional, etc. We came up with a solution to avoid moves here. Basically all of these classes have constructors overload that participate if the contained value is constructible from another object. So we created a helper class that holds a callable and defines a conversion operator to the result type of the callable by calling it (so we get rvo there). With this class, a helper function and a lambda wrapping the original function call we were able to emplace the return value of the function directly into an optional. We did introduce a macro as we did not find it too readable though.
@StanleyPinchak
@StanleyPinchak 4 ай бұрын
Is this similar to the superconstructing super elider technique that Arthur O'Dwyer outlined in his blog?
@FixedTypo
@FixedTypo 4 ай бұрын
@@StanleyPinchak Yes it is actually equivalent to the class with_result_of_t shown in Arthur‘s blog. After hiding the verbosity of invoking the constructor of std::optional with the class and the lambda behind a macro MAKE_OPTIONAL it is actually quite „pretty“. Usage looks like this: MAKE_OPTIONAL(LifeTime{42}) MAKE_OPTIONAL(createLifeTime()) The nice thing is, that you can get direct member initialization too.
@volta948
@volta948 5 ай бұрын
What about std::make_optional?
@furuthebat
@furuthebat 5 ай бұрын
``` std::optional get_value() { return std::make_optional(42); } ``` this works. ``` std::optional get_value() { Lifetime l; return std::make_optional(l); } ``` Same result as with copy-ctor
@bruderdasisteinschwerermangel
@bruderdasisteinschwerermangel 4 ай бұрын
afaik make_optional simply calls the constructor of T with all arguments forwarded to it. So in the first case you're actually calling Lifetime(int) and in the second Lifetime(const Lifetime &), I.e. the copy constructor
@sadunozer2241
@sadunozer2241 4 ай бұрын
I just want you to, I don’t know… regret watching this episode Jason Turner breaks 2024
@VictorYarema
@VictorYarema Ай бұрын
As a result we don't regret watching the episode. We regret that we have to deal with C++ ugliness.
@davidfong
@davidfong 4 ай бұрын
9:47 did you mean to say "more and more implicit conversions" instead of "explicit"?
@cppweekly
@cppweekly 4 ай бұрын
Yes, I did mean implicit
@avramlevitter6150
@avramlevitter6150 5 ай бұрын
Something I'm noticing: your Lifetime class is great at finding out when you might be calling an expensive operation that can't easily be optimized out. When you're using this for a pure value type this all becomes a non-issue. If you have a complicated type, it might be worth seeing if there's an empty state that can be defined and return that (e.g. an empty vector). If you have a complicated type, that's expensive to move, and can't easily have an empty state and you want to add the empty state by sticking it into an optional... then yeah, this is a problem. Personally I haven't run into it yet but that doesn't mean it's not someone else's use case.
@michaelwillett7084
@michaelwillett7084 4 ай бұрын
Ah, I've run into this problem before trying to write unit tests for my own version of std::expected a couple years ago! The problem I ran into is the fact that you are creating an object like Lifetime to track your constructors and destructors / move operators. In doing so, these functions have side effects that the optimizers will explicitly NOT remove, forcing the duplicate constructors and destructors. If you don't have the observers, and just check the pure ASM, then you realize the RVO can kick in and you don't get the extra function calls. I admit that this doesn't help in cases where you do have classes with custom move assignment / construction / destructors, and by definition we end up with the behavior outlined in this video. It doesn't change your point, but there are a lot of cases with default constructors that the simplified code will run just fine with no additional overhead.
@Lol-ld2lu
@Lol-ld2lu 4 ай бұрын
I don't think that calling a move constructor once is worse, than throwing an exception. Move constructor or operator= by their intent should be lightweight. This situation however is not great, but neither as bas as you describe it.
@AdamSzaj
@AdamSzaj 4 ай бұрын
Great episode!
@kuhluhOG
@kuhluhOG 5 ай бұрын
Quite frankly, if it comes to exceptions, I use them for truly exceptional things. But errors are not necessarily exceptional. In quite some cases they are even expected (or at least something which you SHOULD expect). And exceptions are ergonomically REALLY stupid for that and express the intent just way worse than something like std::expected. Disconnecting the "happy" and the "error" path is not always the good thing to do. And expressing programmer intent in code is for 99% of code more important than efficiency, at least imo.
@redcrafterlppa303
@redcrafterlppa303 4 ай бұрын
Any generic result container stands and falls with the level of template deduction the language is capable of. Needing to explicitly type a deeply nested type is a nightmare. I don't know how good cpp is but java has one of the worst. It brakes after 2-3 levels of "templates" requiring a hint in order to compile.
@X_Baron
@X_Baron 5 ай бұрын
It was probably a mistake to make these part of the standard library, instead of language features. Interesting to see if anyone comes up with a workaround.
@MatthewWalker0
@MatthewWalker0 4 ай бұрын
And we could also have built-in arrays that don't have a bunch of pitfalls...
@N....
@N.... 5 ай бұрын
Great video. It's weird that the explicit vs non-explicit constructors seem to be reversed, we can't just write `return {std::in_place, 1};` for best results, but writing `return Lifetime{1}` is allowed and does the wrong thing. I am curious what the committee reasoning is for this strange behavior, I guess maybe they were worried about if the wrapped type also took `std::in_place`
@az-kalaak6215
@az-kalaak6215 5 ай бұрын
well, to be honest I always use optional / variant as a way to return when exceptions is not needed, but code can still fail. but I don't mark the parameter as explicit as those error structs that I use are only used in this context. so no issue for me, but still interesting!
@Qazqi
@Qazqi 4 ай бұрын
This strikes me as something that could potentially have been dealt with via a more explicit Some(foo) and None design for these container types, but I haven't thought through it to pick out whether that's true.
@FlaviusAspra
@FlaviusAspra 4 ай бұрын
I loved the end! Makes me subscribe.
@pancio-ciancio
@pancio-ciancio 2 ай бұрын
Therefore forcing to explicitly construct objects (as convention) can prevent many of this kind of errors?
@cppweekly
@cppweekly 2 ай бұрын
Yes "mark single parameters explicit" has been a best practice for longer than I've been programming in C++. Why doesn't the standard's committee follow this best practice?
@QuickNETTech
@QuickNETTech 4 ай бұрын
I find it interesting that, at 6:48, if you had used an auto return type you would've gotten the behavior you're looking for just coincidentally. Dunno if that's a meaningful observation but I think it makes me want to keep using auto, especially since I don't want to unnecessarily type the return type twice personally.
@piggy8435
@piggy8435 4 ай бұрын
Would love if you could make a video on book recommendations for C++ in 2024
@johnymag666
@johnymag666 4 ай бұрын
Is there a compiler flag to get a warning for these scenarios?
@patlefofort
@patlefofort 2 ай бұрын
I run into a situation where I want to be able to return a struct wrapped with std::expected and initialize it with designated initializers but it's just impossible to do that and avoid copy or move. I just hope the compiler is smart and can optimize it.
@erroneum
@erroneum 4 ай бұрын
I wonder how hard it would be for a compiler to implement a flag that explicitly says you want implicit conversions to standard library containers to fail when it would force an extra object. Obviously that wouldn't be standard compliant behavior, but that's the point of it being a flag (just like -fno-exceptions or -fno-rtti).
@TheDoomista
@TheDoomista 4 ай бұрын
You could propose it as a part of profiles proposal, then it could be in the standard.
@bruderdasisteinschwerermangel
@bruderdasisteinschwerermangel 4 ай бұрын
I guess this is what make_optional and the like are here for Just a shame theyre annoying to use because of just the way they look and also giving you horrible compiler errors when the ctor signature changes
@bruderdasisteinschwerermangel
@bruderdasisteinschwerermangel 21 күн бұрын
What annoys me the most is that when using the make_ family of functions to create the object in place, you can't do aggregate initialization anymore... Nevermind the C++ designated initializers.
@cppweekly
@cppweekly 4 күн бұрын
Any of these "create an object inside of another object" things are a pain to work with efficiently and cleanly in C++
@bruderdasisteinschwerermangel
@bruderdasisteinschwerermangel 4 күн бұрын
@@cppweekly yeah... I sort of accepted that I can either write ctors all day or do an unnecessary move
@garrettkajmowicz
@garrettkajmowicz 3 ай бұрын
If you didn't have the operations being performed in the various constructors, would the compilers be able to optimize those operations away?
@cppweekly
@cppweekly 2 ай бұрын
If the types being contained are trivial, then the discussion is irrelevant. See also: kzfaq.info/get/bejne/mNZ2ZK98tqjLcoU.html
@KillerMZE
@KillerMZE 4 ай бұрын
This episode makes me feel better about my rampant use of raw pointers
@TsvetanDimitrov1976
@TsvetanDimitrov1976 5 ай бұрын
Would using some helper function, like make_optional, or make_expected fix this?
@TsvetanDimitrov1976
@TsvetanDimitrov1976 5 ай бұрын
@@BaardFigur it actually saves some typing sometimes. For example std::optional{std::in_place_t{}, 42} vs std::make_optional(42)
@dshvets1
@dshvets1 5 ай бұрын
Wouldn't make_optional() be a better option?
@catsolstice
@catsolstice 5 ай бұрын
afaik make_optional() need a *public* constructor for the type, which can be an issue
@9uiop
@9uiop 5 ай бұрын
Isn't that practically the same as he did with the one-liner? I guess template argument deduction cannot apply here, so make_optional is even more lengthy to type
@caiovinicius5745
@caiovinicius5745 2 ай бұрын
With expected is even worse! I'm using a static std::expected to construct my object, and having a private constructor, but this blocks me from passing std::in_place + Args, as the constructor is private... How can I apply rvo in this case? will "return std::expected(Class(args)); " work? I tried this and it called the move ctor...
@DerAlbi
@DerAlbi 5 ай бұрын
Btw, RVO is still working! After all, the return value is not copied. What is copied/moved is the thing that belong into the return value. To say that RVO is disabled in these cases is wrong. But overall, you are not wrong with the video. It is not zero-cost abstraction if the actual use-case (and intended use) is not zero overhead. These features basically violate c++.
@xwize
@xwize 4 ай бұрын
If everyone is using it wrong, what does that say about the language
@MarekKnapek
@MarekKnapek 5 ай бұрын
Why there are no `make_optional`, `make_variant`, `make_expected`, `make_unexpected` factory functions? Just like `make_pair`. Function template argument deduction would kick in and I need to write less template stuff. Or is CTAD solving this? Or is thiss non-issue to begin with?
@nickkallen1
@nickkallen1 5 ай бұрын
This is a pretty annoying and significant limitation :(. Accidentally calling copy constructors is one of the major pitfalls of c++
@Mike-gs7eo
@Mike-gs7eo 4 ай бұрын
What happened to good defaults?
@cppweekly
@cppweekly 4 ай бұрын
This is C++
@aniketbisht2823
@aniketbisht2823 5 ай бұрын
6:38 the constructor taking std::inplace_t should also be conditionally explicit. It's tedious to write the whole type name. I usually prefer just returning the value_type of optional but as this video suggests, it might not be as optimal. So std::inplace_t constructor should be used for "non-trivial" value_types but that constructor shouldn't really be explicit.
@N....
@N.... 5 ай бұрын
You can just write `std::in_place`, no need to write the extra `_t{}`, but yes I agree it would be nice to just write `return {std::in_place, 1};`
@georgederleres8489
@georgederleres8489 18 күн бұрын
I am curious whether we can apply the concept to a function that works with some lvalue. For instance assume we have this code : std::optional findUser(const std::vector& users, int id) { for (auto& user : users) { if (user.id == id) { return user; } } return std::nullopt; } Would it be more optimal to write : std::optional findUser(const std::vector& users, int id) { for (auto& user : users) { if (user.id == id) { return std::optional(user); // Constructing optional directly } } return std::nullopt; }
@cppweekly
@cppweekly 4 күн бұрын
reference_wrapper is trivial anyhow, so it's highly unlikely you would ever see a difference between these options.
@mix350
@mix350 5 ай бұрын
Cannot be catch using static analysis like a rule for clang-tidy?
@felixdombek6052
@felixdombek6052 4 ай бұрын
Couldn't you just write `return {Lifetime(42)}`? Same for the std::expected case, just braces around `l` should work?
@Mr.Not_Sure
@Mr.Not_Sure 4 ай бұрын
nope. Still extra object
@raymundhofmann7661
@raymundhofmann7661 5 ай бұрын
Couldn't RVO be generalized to handle these cases with "nested" types? Not changing how i use optional etc. it's not worth it except in very rare cases.
@sinom
@sinom 5 ай бұрын
This really does seem like a language defect. I haven't looked through the papers for these facilities yet but surely they must have at least thought about this issue? There must have been some way that would not have made this an issue even if it qould have required more involved changes
@oschonrock
@oschonrock 5 ай бұрын
Oh dear.. that *is* quite unfortunate.
@pandacongolais
@pandacongolais 4 ай бұрын
I learned something ! Again ! Although not sure I'll ever use it. Am I a bad C++ programmer for avoiding std:: as often as I can ? I place clarity and readability of code over anything else. "Ce que l’on conçoit bien s’énonce clairement. Et les mots pour le dire arrivent aisément" And I never felt any clarity in the use of std:: or the huge error cascades that are (were now days isn't it ?) generated when compiling typos.
@Tibor0991
@Tibor0991 4 ай бұрын
Yes, you are bad, you're writing C++ wrong and decided to cop out of your guilt by shifting the blame to the STL instead. I bet your code is not as clean and readable as much as you think it is and I'm pretty sure I'll bleed from my eye sockets if I ever see it.
@pandacongolais
@pandacongolais 4 ай бұрын
@@Tibor0991 Thanks, time to become a team leader and tell others their code is bad
@Tibor0991
@Tibor0991 4 ай бұрын
@@pandacongolais that's literally what happened to my workplace (before he burned out and left). But srsly, "you don't pay for what you don't use" and the STL rolls by that.
@ujin981
@ujin981 4 ай бұрын
I wonder if there are similar problems in Rust
@somerandompersonintheinternet
@somerandompersonintheinternet 5 ай бұрын
I do regret watching this episode.
@VictorYarema
@VictorYarema Ай бұрын
Don't be. It is not this episode's fault. It is the C++ "standard", which makes things so "great" and "intuitive".
@TheIgoorR
@TheIgoorR 4 ай бұрын
std::make_expected
@scatterarrow
@scatterarrow Ай бұрын
This is the kind of stuff that makes one look for alternatives to c++ or even become a humble avocado farmer instead.
@scatterarrow
@scatterarrow Ай бұрын
Although, I think in most cases, I simply don't care that the move constructor is being called. If I'm writing performance sensitive code, I'm going to be aware of this now. My intuition is to avoid expected there anyway.
@stefanalecu9532
@stefanalecu9532 Ай бұрын
Why avocados?
@victotronics
@victotronics 5 ай бұрын
Interesting issue. How about declaring the return object as "decltype(*this)"?
@Tibor0991
@Tibor0991 4 ай бұрын
Are you 100% certain sure that the print() function isn't making the compiler opting out of optimizations due to unoptimizable side effects?
@cppweekly
@cppweekly 3 ай бұрын
If the types are trivial it all becomes irrelevant, but people rarely go out of their way to make sure the types they use are trivial. If the types are not trivial, normal lifetime rules come into play, this I am 100% certain of. Check out this other video: kzfaq.info/get/bejne/mNZ2ZK98tqjLcoU.html
@MichaelLauerDr
@MichaelLauerDr 4 ай бұрын
Thanks for this insightful episode. Whenever I want to like C++, they‘re doing something like that. 😢
@TheNovakon
@TheNovakon 4 ай бұрын
4:30 - return 42
@wrong1029
@wrong1029 4 ай бұрын
What a mess
@VictorYarema
@VictorYarema Ай бұрын
Some people call it "standard". :(
@Ursus310
@Ursus310 5 ай бұрын
why did you return {42} and not just 42? same for expected just do a if (foo) return 42; else return "not foo"; should work and call the right constructor of explicit (once)
@xiao_sings
@xiao_sings 5 ай бұрын
That’s crazy
@chengjiwei
@chengjiwei 4 ай бұрын
Regretted watching this, hahaha
@anon_y_mousse
@anon_y_mousse 4 ай бұрын
This is one of the things that I've always hated about C++ and that I've hopefully made better in my own language with more inference. I guess you could say in my language I infer all the things.
@FloodAnxiety
@FloodAnxiety 4 ай бұрын
Yeah... I do regret watching this video. I went from, oh interesting, oh do I have problems I need to fix now? to oh wait... no, implicit brace initialization works, he had to make it explicit for it to not work... so... I think we are fine? Wait... what did I learn from this? I guess I gained worry that I am missing something?
@FloodAnxiety
@FloodAnxiety 4 ай бұрын
Well, Print(const std::source_location& location = std::source_location::current()) was cool, I'd never seen that before.
@phenanrithe
@phenanrithe 4 ай бұрын
No, I'm not.
@markusasennoptchevich2037
@markusasennoptchevich2037 4 ай бұрын
That's why any serious library or project are written in C, not C++. You cannot expect what instructions compiler will generate without going insane with C++
@Debrugger
@Debrugger 4 ай бұрын
This language is insane lol
@leshommesdupilly
@leshommesdupilly 5 ай бұрын
Virgin std::variant fan vs Chad void* + c-style cast enjoyer
@aniketbisht2823
@aniketbisht2823 5 ай бұрын
While using heap to allocate your object (that you're returning a void* pointer to). Yeah, right.
@marce3893
@marce3893 5 ай бұрын
always resort to the 20-50 constructs of C instead of learning newer useful constructs. make sure to dismiss them as idiomatic C++ complexity too... (don't take it personally, I never meant it. I understand your comment's meant to be a joke. I just want to say it's a bad joke :P )
@Evan490BC
@Evan490BC 4 ай бұрын
@@marce3893You are right and wrong at the same time (in a nice Schrödinger-esque way) 🙂. C++ does automate many things *but* the idiomatic complexity of C++ is indeed insane!
@alskidan
@alskidan 5 ай бұрын
C++ Weekly - Ep 422 - Moving from C++20 to C++23
13:38
C++ Weekly With Jason Turner
Рет қаралды 10 М.
C++ Weekly - Ep 404 - How (and Why) To Write Code That Avoids std::move
8:50
C++ Weekly With Jason Turner
Рет қаралды 28 М.
Meet the one boy from the Ronaldo edit in India
00:30
Younes Zarou
Рет қаралды 15 МЛН
Box jumping challenge, who stepped on the trap? #FunnyFamily #PartyGames
00:31
Family Games Media
Рет қаралды 33 МЛН
ISSEI & yellow girl 💛
00:33
ISSEI / いっせい
Рет қаралды 21 МЛН
黑天使遇到什么了?#short #angel #clown
00:34
Super Beauty team
Рет қаралды 43 МЛН
C++ Weekly - Ep 322 - Top 4 Places To Never Use `const`
18:53
C++ Weekly With Jason Turner
Рет қаралды 35 М.
The Pointer to Implementation (pImpl) idiom in C++
6:54
platis.solutions
Рет қаралды 14 М.
C++ Weekly - Ep 312 - Stop Using `constexpr` (And Use This Instead!)
18:24
C++ Weekly With Jason Turner
Рет қаралды 51 М.
C++ Weekly - Ep 410 -  What Are Padding and Alignment? (And Why You Might Care)
9:48
C++ Weekly With Jason Turner
Рет қаралды 14 М.
Compilers, How They Work, And Writing Them From Scratch
23:53
Adam McDaniel
Рет қаралды 153 М.
C++ Weekly - Ep 332 - C++ Lambda vs std::function vs Function Pointer
16:30
C++ Weekly With Jason Turner
Рет қаралды 32 М.
Cursed C++ Casts
17:41
Logan Smith
Рет қаралды 72 М.
WHY did this C++ code FAIL?
38:10
The Cherno
Рет қаралды 250 М.
C++ Weekly - Ep 363 - A (Complete?) Guide To C++ Unions
16:14
C++ Weekly With Jason Turner
Рет қаралды 14 М.
Meet the one boy from the Ronaldo edit in India
00:30
Younes Zarou
Рет қаралды 15 МЛН