Classes part 10 - Rule of Five - Have fun reducing memory allocations! | Modern Cpp Series

Sdílet
Vložit
  • čas přidán 18. 05. 2024
  • ►Full C++ Series Playlist: • The C++ Programming La...
    ►Find full courses on: courses.mshah.io/
    ►Join as Member to Support the channel: / @mikeshah
    ►Lesson Description: In this lesson I discuss the rule of five (otherwise known as the law of 5 or the big 5). I first will recap a simple class data structure recapping the big 3 (constructor, destructor, and copy constructor), and showing where these special member functions are invoked. Then I will remind you of the idea of move semantics (i.e. the transfer of resources from one object to another). When used appropriately, move semantics can save significantly on performance by avoiding copies. Towards the end of the lesson, I will show you how copies are often made, and sometimes unknowingly (like in the case of a vector when it is getting resized as you add elements), and how move semantics can help significantly improve performance by reducing allocations.
    ►CZcams Channel: / mikeshah
    ►Please like and subscribe to help the channel!
  • Věda a technologie

Komentáře • 52

  • @FabrizioSellone
    @FabrizioSellone Před 2 lety +5

    Excellent example Mike. Neat, plain, simple, fast and complete. I would really appreciate if you can post a similar video showing all the possible ways to build a vector (or any other STL container for that matter) of objects in C++ highlighting the best practice to do so. You can create vectors of objects from the stack or from the heap, you can use move semantics, you can use objects themselves or pointers to them, etc … Many possibilities here, but what is the best way of doing things ? Thanks for these very good and informative videos!

    • @MikeShah
      @MikeShah  Před 2 lety +3

      Thank you for the kind words! Coming up in the series will eventually be talking about STL and these general data structures available. Then I've noted your request, as at some point this is the kind of video that could go into a Data Structures Playlist for C++.

  • @k0185123
    @k0185123 Před 2 měsíci +1

    After watching this video, I really should familiarize myself with the std::move!!

  • @nishant1877
    @nishant1877 Před rokem +2

    Wonderful series
    Been on a binge watch since yesterday

  • @dhanushs1802
    @dhanushs1802 Před rokem +1

    Wonderfully explained as always. Thank You.

    • @MikeShah
      @MikeShah  Před rokem

      Cheers, thank you for the kind words!

  • @Southpaw101
    @Southpaw101 Před rokem

    Great explanation!

  • @shrek1412
    @shrek1412 Před rokem +1

    very useful, thanks Mike

  • @zionen01
    @zionen01 Před 3 měsíci +2

    This cleared up a confusion I had about the move operation. It didn't make sense to me, why would we reset variables of the source if the destination was claiming its memory, it seemed as if resetting source was resetting destination. But then I see, it's only for heap allocated memory that move operations truly moves, whereas stack variables are copied. Thanks for the video.

  • @rdd-technical6824
    @rdd-technical6824 Před rokem +1

    You should also declare the move constructors noexcept so that when using the struct in STL containers it will not default to copying

    • @MikeShah
      @MikeShah  Před rokem

      Correct! I haven't covered noexcept yet in this series. It's probably the right default in C++ to be honest

    • @rdd-technical6824
      @rdd-technical6824 Před rokem +1

      @@MikeShah Yeah just wanted to put that comment in there so anyone who watches this vid knows to do so. I am loving the series and learning some great things, thank you for making these

    • @MikeShah
      @MikeShah  Před rokem

      @@rdd-technical6824 Cheers and absolutely -- I'm sure that's going to help future folks out :)

  • @TechTricks1992
    @TechTricks1992 Před 7 měsíci +1

    Hi Mike, why you just assigned data directly in move constructor instead of creating a new memory and copying content inside it. To me it seems we are doing shallow copy here. And due to that only valgrind reported less memory allocations.

    • @letslearn1703
      @letslearn1703 Před 7 měsíci

      @MikeShah I have the same doubt. Please comment on it

  • @syounes
    @syounes Před 11 měsíci

    Excellent example!!!! 46 lessons have been completed, 87 lessons left. *FIGHTING

  • @RahmanianMohammad
    @RahmanianMohammad Před 6 měsíci +1

    very excellent lecture. Thanks Mike.
    In the move assignment operator implementation, should we be freeing the allocated memory by calling `delete[] m_data` before assigning m_data to source.m_data?
    In the copy assignment operator, we freed the memory using delete[] m_data. Shouldn't we follow the same practice in the move assignment operator?

    • @MikeShah
      @MikeShah  Před 6 měsíci

      Should not need to free the data, we are just re-assigning the pointer -- move assignment thus is faster, as it's taking over ownership of the data without having to reallocate. Old m_data then points to nothing (i.e. no 'sharing' or 'moving' of data -- it is effectively empty or nullptr)

    • @mingxue6327
      @mingxue6327 Před 2 měsíci +2

      @@MikeShah, if move assignment is invoked, valgrind will show memory leaks. Before repointing, the existing memory needs to freed for assignment. Your example only used move constructor. Also, better to use std::move on the string member m_name and no need to assign it to "" afterwards either.

    • @MikeShah
      @MikeShah  Před 2 měsíci

      Correct, do need to eventually free the data, just not after 'moving' it (so still need to do so in the destructor of whoever owns the memory)@@mingxue6327

  • @glaze4629
    @glaze4629 Před 5 měsíci

    I'm very new to C++ mostly with Java knowledge, I wonder why would one chose to define unimplemented constructors, I understand the point of interfaces but what's the need for a constructor with no implementation?

  • @windowsbuilderthegreat3121

    Could you please make a video on how to call a WebAPI in C++

  • @robertstrickland9722
    @robertstrickland9722 Před rokem +1

    Since the move constructor transfers ownership and the original allocated object is being nullified, wouldn't it be even more efficient, in terms of size of allocated memory, to delete the original afterwards?

    • @MikeShah
      @MikeShah  Před rokem

      One thing to keep in mind is that 'moving' is not equivalent to 'destroying' an object. The nullified object will otherwise be reclaimed by the destructor and save memory in that way. I suppose if there was some way to know exactly how many objects you needed, you would save stack space when allocating those objects to otherwise not allocate them, and just keep the object you need that owns the memory you'll need. Pool allocators for example are designed to optimize for allocatations where you may have a fixed size number of objects, and otherwise can avoid major reallocations by just transferring and 'recyling' (i.e. moving) memory around.

  • @karm0s304
    @karm0s304 Před rokem +2

    Hey Mike, amazing video! You really helped me understand the rule of 5 better. I am just wondering why you didn't delete the array before giving m_data the new value. Doesn't that lead to a memory leak ?

    • @MikeShah
      @MikeShah  Před rokem +1

      Cheers! At what timestamp are you referring?

    • @karm0s304
      @karm0s304 Před rokem +1

      @@MikeShah At 14:42, line 51 in the move assignment operator method.

    • @MikeShah
      @MikeShah  Před rokem +1

      @@karm0s304 When we 'move assign', we are transferring ownership. So I don't want to destroy the data, but rather only have one pointer to the data. If I delete the data, then the data will be null :) Remember the '=' with a pointer type is simply updating the pointer to the memory. Note also, for the 'std::string' m_name, I am using an '=' sign to transfer ownership, but the move-assignment operator that has implemented in std::string should do the proper 'move-assignment' for us (as opposed to a copy).

    • @karm0s304
      @karm0s304 Před rokem +1

      ​@@MikeShah Thanks for your reply ! Actually I am talking about the old data that m_data was holding before giving it the new pointer. If I understood correctly, the move assignment operator method will be called when we try to move an object into another existing object. Let's say I try to move B into A, object A's m_data will have a pointer to an array of 10 elements, so if we move the value of B's m_Data into A's m_Data without deleting the old array that A was holding that would cause a memory leak.
      The only place where we could directly do that is in the move constructor because the receiving object didn't allocate any data before.

    • @MikeShah
      @MikeShah  Před rokem +1

      Ah, yes you're correct. For the move-assignment operator we should delete[] beforehand (because we are the owner in this example)

  • @BlakeSekelsky99
    @BlakeSekelsky99 Před měsícem

    In the move assignment operator, it makes sense why m_data from the source would be set to nullptr to avoid a double delete error in the destruction of the object. Running through valgrind it shows more allocations than frees when calling a move assignment. But when I switch to using std::move on m_data, valgrind still shows that there is unfreed memory - but now has equal allocations to frees. Any insights into what is happening? Also, would this be considered leaking data, or just the natural consequence of allocating memory just to reassign it in this example?

    • @MikeShah
      @MikeShah  Před měsícem

      Interesting -- I wonder if that is a bug? As long as it's showing that all memory is freed that should be okay however (i.e. no leaks detected).

  • @AlexanderWhillas
    @AlexanderWhillas Před 2 lety +1

    Nice video. I'm a bit confused as to how you would move a unique_ptr?

    • @MikeShah
      @MikeShah  Před 2 lety +1

      A unique_ptr itself can be moved (not copied however). So you could do something like: std::unique_ptr object1 = std::move(object2); in your move-assignment constructor. This might provide some insight: docs.microsoft.com/en-us/cpp/cpp/how-to-create-and-use-unique-ptr-instances?view=msvc-170

  • @praveenpragya9360
    @praveenpragya9360 Před 2 měsíci +1

    Hi ​ @MikeShah at 8:30 , can you please explain how you returned result from foo(), as the function foo() has return type of IntArray, BUT at it's call from main(), you have not written any variable to store it, isn't it an error or warning?

    • @MikeShah
      @MikeShah  Před 2 měsíci

      If I mark the function as nodiscard, then a warning will be given since the returned value is not used.

    • @praveenpragya9360
      @praveenpragya9360 Před 2 měsíci +1

      @@MikeShah Thank you so much 😁

  • @looploop6612
    @looploop6612 Před 7 měsíci +1

    what is that operator= used for ?
    I did not see it get called .

    • @MikeShah
      @MikeShah  Před 7 měsíci

      Used for assignment for already created objects to copy

  • @TechTricks1992
    @TechTricks1992 Před 7 měsíci

    Hi @MikeShah, why you just assigned data directly in move constructor instead of creating a new memory and copying content inside it. To me it seems we are doing shallow copy here. And due to that only valgrind reported less memory allocations.

    • @MikeShah
      @MikeShah  Před 7 měsíci +1

      Move assignment or move constructor is in fact doing a shallow copy -- it's fast! But along with the shallow copy, we are changing ownership, such that the new object has control of the data, and the other object we are moving from, then does not 'own' the memory.

    • @TechTricks1992
      @TechTricks1992 Před 7 měsíci +1

      @@MikeShah thanks for your reply Mike. I have one more question can we move construct an object from itself?

    • @MikeShah
      @MikeShah  Před 7 měsíci

      Hmm, there is a move constructor, but not sure if it could move from itself while being constructed -- do you have a use case?

    • @TechTricks1992
      @TechTricks1992 Před 7 měsíci +1

      @@MikeShah Hi Mike thanks for your reply, I don't have a use case at present.