Thanks Andre, appreciate your time and effort sharing your knowledge of the C++ language. Whilst I am very familiar with the rules of 3/5/0, it is often nice to challenge and remind oneself of their knowledge and assumptions.
Thank you so much. Cleared a lot of doubts. Took screen prints of Rule of 5 and the table of special methods provided by compiler vs ones provided by the user. Can't thank you enough. Saved me a lot of reading and going round in circles to nowhere
The question that soon arises for maintainers of older code soon becomes: If the code was already written correctly complying with the Rule of Three, will it still be safe with the new compiler without any changes? As far as I can understand - based on the chart - it still should be. You just don't get the benefit of move semantics. It can be a bit more fuzzy when inheritance is involved, and maybe one of the base classes has been "upgraded" to the Rule of Five, not to mention when some of the methods may be declared virtual too. Larger codebases often find themselves in such a mixed "transition state" after the passage of time and many programmers have left their mark.
When you move to the new compiler, the presence of the copy operations would cause the move operations to be not declared. So attempts to move would "fall back" to the copies.
Would it make sense in implementing sstring to use std::vector as the container type? Implementing Estring to use string feels like a bit of a cop-out answer here... but I'm not sure if std::vector would be enough as I honestly haven't carefully considered it. I would think it would get us close with copy/move semantics though, and it still has access to the pointer through the data() member(or something with a similar name?) iirc.
Would it make sense for SString? No, because SString is supposed to be the example to talk about a "broken" implementation. Could you use it in EString? Sure. std::vector behaves correctly using the rule of 0. Whether either of these would constitute a "good" string class is beyond the scope of the talk.
@@AndreKostur I don't think the point for it was to be broken, just simplified(like std::string but worse) and showing the incremental improvements. EString or extended string was called such as it utilized composition to wrap std::string with extra functionality, rather than working with more primitive base components I thought? Unless I'm misunderstanding here? He also said that he stepped away from simple string to extended string as he didn't find a nice way to represent that. That's what I was asking about when I asked if it made sense to use that(as a nice way to represent that). I think we can both agree that this isn't a 'good' way to write a string class as there is a lot more to them typically, including short string optimizations that we are completely ignoring here, but for the purposes of this talk on the rules of 0, 3, and 5 I was wondering if it would be a nice way to represent the string that handles it correctly. Based on your response though, it sounds like it would behave as expected with the rule of 0 if I'm understanding right? ((I am not familiar with all the nuances of the compiler's auto generated constructor definitions when using std::vector, which is mostly why I'm not sure, but I *think* if I understood this talk right, it should work as expected?)) That was more what I was wondering.
@@Firestar-rm8df Yep, using std::vector as the final refinement to SString to make it work with the rule of 0 would work fine. It knows how to copy, move, and destroy itself well.
Around 32:00 Andre talks about a class that the developer wants to use the copy constructor or assignment operator when moving and suggests commenting out the move constructor and move assignment operator to get that behaviour. Would it be possible to =default the move constructor and move assignment operator to get the same result?
No. If you =default the moves, then they would be present and thus move operations would call those (compiler-generated) functions instead of the copy operations. And the idea was that one wanted to force everything through the copy operations.
I wonder if there is a proposal for some kind of `value_ptr` which is like `unique_ptr` except it can be copied by copying the underlying data to a new allocation, possibly with a custom allocator similar to a custom deleter.
I just created one of these the other day. I called it HeapObject. It knows how to copy and move itself, and it supports declaring an inherited class, and it looks to see if a function is defined for copying the inherited type and if not, defaults to using operator=, it also will implicitly cast to T* and explicitly cast to any other type of pointer, and it defines operator* and operator-> I'm also going to do this with a reference type Reference, and a HeapArray, and I'm pretty sure once I do that, every singel class in my code base will fall under the rule of 0
6:41 But you see, I will never construct an allocation function in a manner like this to make a leak. Most of my memory allocation will have a simple step to later delete. In any case, I will never have a constructor with routines, without a destructor with the opposing routines new/delete new[]/delete[], open/close etc
The class' intent on copying is to end up with two separate instances (separate copies of the data) of a string. But if you copy the shared_ptr, what you end up with two strings that are sharing the _same_ data. Which means that when you change one of them, the other one is also "changed" since the two are sharing the data.
I want to learn C++ but the more I learn either from books or elsewhere the more it seems like C++ is a language that wrote itself into a corner of bad decisions and now can't fix them because it has to keep backwards compatibility and people can't switch because nothing else with the same use cases is as developed (or widely used) as it. Like all this would be so much easier and less error prone if the compiler didn't create or remove different things depending on a myriad of factors but just expected you to define what you need and to manually tell it to provide defaults (or mark as intentionally not implemented) for what you didn't.
@20:30 This also sounds incorrect. "If you don't provide one [move assignment operator], the compiler will move-assign each of your member variable". Is this behavior simply true?
You are right, I misspoke. The intent of this example was to illustrate the preceeding statement about classes which take away the copy operations. std::unique_ptr is movable, but not copyable. Good catch!
@@IsaacC20 Assuming that one hasn't provided copy operations, or the other move operation, or a destructor, yes. What situation are you concerned about?
Petition to all c++ programmers: PLEASE FOR THE LOVE OF GOD dye your hair blue and become rust cultist, so the humanity doesn't have to deal with this mess anymore
It is kinda ASMR which is nice. What is the point to this talk? It very slowly describes how to deal with dynamic memory with lots of repetition. .... I guess the take away is: memory management in c++ is a nightmare.... This is why the Whitehouse says to not use c++ 😉 .... And btw what is the rule of 5? .... Switching example in the middle?! So... You implemented a string using a string class. Huh?
What is the Rule of 5? Slide 20 @15:50. Rule of 5 applies to any case where you do something special in any of the 5 special members. Manual dynamic memory handling is probably one of the easiest examples for the intended audience to generally immediately understand.
Thanks. Useful, Interesting, Calm talk.
Great talk! Always nice to get a refresher on the basics. The examples clearly show the usage of the rule. Looking forward to your 2024 talk.
I love these B2B videos. And this one is long overdue! Thanks, Andre!
I really like the idea of back to basics section. This talk fits perfectly to help me understand.
Great talk! Very clear and well explained.
Thanks Andre, appreciate your time and effort sharing your knowledge of the C++ language. Whilst I am very familiar with the rules of 3/5/0, it is often nice to challenge and remind oneself of their knowledge and assumptions.
thanks, great talk
Great talk, thank you!
37:25 Since C++20, a class with user-declared constructors is considered not to be an aggregate. ("= default" is still user-declared.)
Thank you so much. Cleared a lot of doubts. Took screen prints of Rule of 5 and the table of special methods provided by compiler vs ones provided by the user. Can't thank you enough. Saved me a lot of reading and going round in circles to nowhere
Great talk, thank you so much, I really enjoyed!
Came for entertainment, Found gold. Immediately smashed that like button
informative and important cppCon topic.. however, the few of the last QnA wasn't clear without real example/code.
The question that soon arises for maintainers of older code soon becomes:
If the code was already written correctly complying with the Rule of Three, will it still be safe with the new compiler without any changes?
As far as I can understand - based on the chart - it still should be. You just don't get the benefit of move semantics. It can be a bit more fuzzy when inheritance is involved, and maybe one of the base classes has been "upgraded" to the Rule of Five, not to mention when some of the methods may be declared virtual too. Larger codebases often find themselves in such a mixed "transition state" after the passage of time and many programmers have left their mark.
When you move to the new compiler, the presence of the copy operations would cause the move operations to be not declared. So attempts to move would "fall back" to the copies.
Would it make sense in implementing sstring to use std::vector as the container type? Implementing Estring to use string feels like a bit of a cop-out answer here... but I'm not sure if std::vector would be enough as I honestly haven't carefully considered it. I would think it would get us close with copy/move semantics though, and it still has access to the pointer through the data() member(or something with a similar name?) iirc.
Would it make sense for SString? No, because SString is supposed to be the example to talk about a "broken" implementation. Could you use it in EString? Sure. std::vector behaves correctly using the rule of 0. Whether either of these would constitute a "good" string class is beyond the scope of the talk.
@@AndreKostur I don't think the point for it was to be broken, just simplified(like std::string but worse) and showing the incremental improvements. EString or extended string was called such as it utilized composition to wrap std::string with extra functionality, rather than working with more primitive base components I thought? Unless I'm misunderstanding here? He also said that he stepped away from simple string to extended string as he didn't find a nice way to represent that. That's what I was asking about when I asked if it made sense to use that(as a nice way to represent that). I think we can both agree that this isn't a 'good' way to write a string class as there is a lot more to them typically, including short string optimizations that we are completely ignoring here, but for the purposes of this talk on the rules of 0, 3, and 5 I was wondering if it would be a nice way to represent the string that handles it correctly. Based on your response though, it sounds like it would behave as expected with the rule of 0 if I'm understanding right? ((I am not familiar with all the nuances of the compiler's auto generated constructor definitions when using std::vector, which is mostly why I'm not sure, but I *think* if I understood this talk right, it should work as expected?)) That was more what I was wondering.
@@Firestar-rm8df Yep, using std::vector as the final refinement to SString to make it work with the rule of 0 would work fine. It knows how to copy, move, and destroy itself well.
Around 32:00 Andre talks about a class that the developer wants to use the copy constructor or assignment operator when moving and suggests commenting out the move constructor and move assignment operator to get that behaviour. Would it be possible to =default the move constructor and move assignment operator to get the same result?
No. If you =default the moves, then they would be present and thus move operations would call those (compiler-generated) functions instead of the copy operations. And the idea was that one wanted to force everything through the copy operations.
I wonder if there is a proposal for some kind of `value_ptr` which is like `unique_ptr` except it can be copied by copying the underlying data to a new allocation, possibly with a custom allocator similar to a custom deleter.
I just created one of these the other day. I called it HeapObject. It knows how to copy and move itself, and it supports declaring an inherited class, and it looks to see if a function is defined for copying the inherited type and if not, defaults to using operator=, it also will implicitly cast to T* and explicitly cast to any other type of pointer, and it defines operator* and operator->
I'm also going to do this with a reference type Reference, and a HeapArray, and I'm pretty sure once I do that, every singel class in my code base will fall under the rule of 0
For a SString you could get rule of zero by using std::vector
6:41 But you see, I will never construct an allocation function in a manner like this to make a leak. Most of my memory allocation will have a simple step to later delete. In any case, I will never have a constructor with routines, without a destructor with the opposing routines new/delete new[]/delete[], open/close etc
the start is at 5:41
I'm not sure I got what was the issue with the shared_ptr version of Simple String (21:47 - Slide 27)
The class' intent on copying is to end up with two separate instances (separate copies of the data) of a string. But if you copy the shared_ptr, what you end up with two strings that are sharing the _same_ data. Which means that when you change one of them, the other one is also "changed" since the two are sharing the data.
I want to learn C++ but the more I learn either from books or elsewhere the more it seems like C++ is a language that wrote itself into a corner of bad decisions and now can't fix them because it has to keep backwards compatibility and people can't switch because nothing else with the same use cases is as developed (or widely used) as it. Like all this would be so much easier and less error prone if the compiler didn't create or remove different things depending on a myriad of factors but just expected you to define what you need and to manually tell it to provide defaults (or mark as intentionally not implemented) for what you didn't.
I feel like the entire special member functions are not that well implemented in C++ considering we get a talk about the rule of 5 every second cppcon
@19:45-19:49 This sounds incorrect. Can someone verify std::unique_ptr is NOT copyable and IS movable?
@20:30 This also sounds incorrect. "If you don't provide one [move assignment operator], the compiler will move-assign each of your member variable". Is this behavior simply true?
You are right, I misspoke. The intent of this example was to illustrate the preceeding statement about classes which take away the copy operations. std::unique_ptr is movable, but not copyable. Good catch!
@@IsaacC20 Assuming that one hasn't provided copy operations, or the other move operation, or a destructor, yes. What situation are you concerned about?
1. don't use multiple inheritance
2. don't use operator overloading
3. don't use templates
4. don't use lambdas
5. don't use C++ at all.
Petition to all c++ programmers: PLEASE FOR THE LOVE OF GOD dye your hair blue and become rust cultist, so the humanity doesn't have to deal with this mess anymore
It is kinda ASMR which is nice. What is the point to this talk? It very slowly describes how to deal with dynamic memory with lots of repetition. .... I guess the take away is: memory management in c++ is a nightmare.... This is why the Whitehouse says to not use c++ 😉 .... And btw what is the rule of 5? .... Switching example in the middle?! So... You implemented a string using a string class. Huh?
What is the Rule of 5? Slide 20 @15:50. Rule of 5 applies to any case where you do something special in any of the 5 special members. Manual dynamic memory handling is probably one of the easiest examples for the intended audience to generally immediately understand.
Time to move on from C++ to better, more modern languages. It's had a good run. Time for it to retire.
it's the king of all, others are made with either C or C++ or assembler.
Get out of here rust fanboy!
Cpp will never die 😤
i use string_view and i dont have problem
The example presented is contrived - we can use std::string. We can't use a string_view variable when we want that variable to own the data as well.