Safely copying, moving, and destroying objects in Modern C++ with the rule of "all or nothing"

Поделиться
HTML-код
  • Опубликовано: 13 сен 2024
  • Which constructors does a C++ class need? Which does it generates on its own? What about various assignment operators? And a destructor? How not to shoot ones leg off and navigate these waters effortlessly?
    This and more we cover in this video that tells us a simple rule to follow when implementing classes in Modern C++, the rule of "all or nothing". We dive into the reasons for its existence and see how it makes our lives easier.
    📚 As always, the script to the video lives here: github.com/cpp...
    Related videos and materials:
    - Move semantics video: • Re-inventing move sema...
    - Object lifecycle video: • C++ object lifecycle 1...
    - Raw pointers video: • Mastering C++ pointers...
    - Google style on naming: google.github....
    - Rule of 5/3/0 on cppreference.com: en.cppreferenc...
    - Rule of all or nothing from Arne Mertz blog: arne-mertz.de/...
    - CPP Core Guidelines on the rule of 5, rule of 0: isocpp.github.i...
    The frustrated person video clip is from pexels.com

Комментарии • 16

  • @zamf
    @zamf Год назад +3

    Great explanation once again. Very brief and down to the point without much diving onto details.
    I have one small comment (it is more of an aesthetic improvement): at 9:27 when writing the move constructor it is a good idea to use std::move in the member initialization list to further emphasize on the fact that you're moving data and you're not copying it. In your example it doesn't matter because moving and copying pointers and size_t variables is the same (it produces the same assembly code) but if you change the type of the members to something more complex and you forget to call std::move in the move constructor you'll get a copy instead. It's a bit more typing but it can protect you from doing unnecessary copies by accident.

    • @CodeForYourself
      @CodeForYourself  Год назад +1

      Thanks for the compliment!
      You do make a good point here! I tend to not use std::move on fundamental types and pointers bit I agree that this might be confusing to beginners. I will add it to the sticky comment and will update the script.

  • @CodeForYourself
    @CodeForYourself  Год назад +1

    Hey everyone! Had to re-upload this one due to a mistake I made. 😅 Please do leave any feedback on the video in the comments, it helps me a lot and has a direct influence on future videos! 🙏
    There are some improvements that have been suggested and I want to post them here:
    - when implementing the move constructor it is a good idea to explicitly use std::move when passing arguments to the initializer list. This makes no change for simple types but plays a role for bigger types.

  • @Evan490BC
    @Evan490BC Год назад +3

    Igor, I just realised what the colours in your logo mean. I can't help it, so Слава Україні!, from the UK.

    • @CodeForYourself
      @CodeForYourself  Год назад +1

      Yeah, the original logo that I thought of was gray. I changed it on the 24th of February last year. Until Ukraine wins it stays like that. And of course: Героям слава!

  • @Pror0ckCoding
    @Pror0ckCoding Год назад

    I would also notice, that if an exception will be thrown in the constructor after the memory allocation a memory leek would still occur. So, you should use std::unique_ptr or something like this to make it deallocating automatically in such cases

    • @CodeForYourself
      @CodeForYourself  Год назад +2

      Yeah, using unique ptr is nearly always better than managing resources by hand. But I had to use raw pointers here in order to explain what I actually wanted to explain here.

  • @faridmehrabi2761
    @faridmehrabi2761 Год назад

    I prefer the term **rule of 0/3/5**, 5 is only useful when you need to optimize the behavior. Move-only and none movable classes need not declare copy member functions, declaring a move member function implicitly `delete`s them. Finally, the **copy/swap** idiom for beginners is a good start point with rule of 3; combined assignment can avoid identity check by accepting its argument as value rather than a reference and eventually decrease 5 to 4. Self assignment is rare, and the penalty of occasional unnecessary copy - due to self assignment - can be justified by removing a branch statement in cpu instruction pipeline.

    • @CodeForYourself
      @CodeForYourself  Год назад +1

      I see what you mean, but I would still stick with the rule of "all or nothing". Relying on something being implicitly declared is not very beginner friendly in my experience. It requires some unspecified implicit knowledge that beginners usually don't have. What is worse: they don't know that they should have it which leads to mistakes that can easily be avoided.
      As for the copy swap idiom I mostly agree with you but I've seen a lot of beginners being confused by it, so it did not make it into this video. And to be honest these things are so intricate that I don't think I can't give a rule that just works all the time here. I'd say it has to be measured and researched if it becomes a bottleneck.

  • @gordonfreimann
    @gordonfreimann Год назад

    I remember there was a way to disable some of the constructors explicitly if we dont want to implement one but still want the class to be memory safe.

    • @CodeForYourself
      @CodeForYourself  Год назад +2

      Yes, one can use =delete. We will talk about it once we have a use for this functionality 😉

    • @segfault4568
      @segfault4568 Год назад +1

      I used to delete them when working with singletons, mostly entity managers for games.

  • @ElPikacupacabra
    @ElPikacupacabra 7 месяцев назад

    Maybe the "helpful compiler" should not be so helpful. 😂

    • @CodeForYourself
      @CodeForYourself  7 месяцев назад +1

      Well, there are good reasons for it to be this helpful I would say 😉

    • @ElPikacupacabra
      @ElPikacupacabra 7 месяцев назад

      @@CodeForYourself Yeah, the C++ defaults are probably wrong. This is what I was getting at.

    • @CodeForYourself
      @CodeForYourself  7 месяцев назад +1

      @@ElPikacupacabra I wouldn't go as far as call them "wrong". They don't always align with the current best practices. But such best practices change. While back compatibility remains an important feature of the language. The current defaults mostly exist to enable that back compatibility if you ask me.