Back to Basics: Move Semantics (part 1 of 2) - Klaus Iglberger - CppCon 2019

Sdílet
Vložit
  • čas přidán 1. 08. 2024
  • CppCon.org
    Discussion & Comments: / cpp
    Presentation Slides, PDFs, Source Code and other presenter materials are available at: github.com/CppCon/CppCon2019
    -
    Back to Basics: Move Semantics (part 1 of 2)
    Move semantics is one of the most complex topics in the world of C++, including many technical details that often confuse even experts. This interactive back-to-the-basics session is entirely focused on understanding the details behind move semantics. It explains the motivation behind move semantics, the need for rvalue references and std::move, the reason for forwarding references and std::forward, and how to properly apply move semantics. The many interactive questions and exercises will help to quickly adapt the newly gained knowledge.
    -
    Klaus Iglberger
    Klaus Iglberger is a freelancing C++ trainer and consultant and is currently on the payroll of Siemens in Nuremberg, Germany. He has finished his PhD in computer science in 2010 and since then is focused on large-scale C++ software design. He shares his experience in popular advanced C++ courses around the world (mainly in Germany, but also the EU and US). Additionally, he is the initiator and lead designer of the Blaze C++ math library (bitbucket.org/blaze-lib/blaze...) and the organizer of the Munich C++ user group (www.meetup.com/MUCplusplus/).
    -
    Videos Filmed & Edited by Bash Films: www.BashFilms.com
    *-----*
    *--*
    *-----*
  • Věda a technologie

Komentáře • 78

  • @norikazuoshiro6324
    @norikazuoshiro6324 Před 4 lety +128

    Man i really love these back to basics series talks (specially this one and the RAII by Arthur). Helps me a lot as C++ beginner

    • @landondyer
      @landondyer Před 3 lety +15

      I've been using C++ since the 1980s, and it still helps me :-)

    • @masheroz
      @masheroz Před 2 lety

      This one? czcams.com/video/7Qgd9B1KuMQ/video.html

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

      @@landondyer I had to learn C++ programming back in 2002 - 2003 for my 3rd year University subject called OOP and data structures. After I had passed that exam I didn't really use C++ for about 10 years. Picked it up again sometime in 2014-2015 when I decided I needed to dive deeper into the gritty - nitty details of C++'s language semantics, syntax rules and the C++ memory model. Have been using this wonderful powerful programming language ever since. I really love all the modern C++ language features especially those that were introduced with the first 3 modern C++ language standards (C++11, C++14 and C++17). At the moment I'm in the process of getting acquainted with all the new C++ language and library features that were introduced with the C++ 20 standard.

    • @b1ueocean
      @b1ueocean Před rokem

      @@atib1980 we did OOP in my second year as 1st year Intro to Programming switched to Java - our learning materials were still in pre-print. Like you, after uni I left C/C++ behind - but I had been doing C/C++/ASM since I was 15.
      I’m shocked that the language, although “modernised”, still looks absolutely horrible to read and requires several scans of lines, parameters, modifiers, syntaxes and so on to properly figure out what code is doing. Not looks like it is doing but is actually doing.
      My SAAS backend is in C++ interfacing with a SPA Frontend. For the sanity of myself and others, functionality at the back relies heavily on an in-house framework to standardise everything - die hard C++ers will use and abuse everything available if you let them and render the codebase horrible for consumption by others that know it pays to keep things simple 🙂
      I do love the performance I get at runtime though - my end to end round trips are lightening fast allowing the Frontend to operate extremely responsively and seamlessly 👍
      One thing I had to sort out straight away was dependency management and build workflow. Ended up throwing away makefiles and using Maven which has been ok so far.
      “mvn clean package” gives me shareable libraries and executable binaries for AMD64, AARCH64, Linux and Windows with compile-time Native ARchive dependencies pulled in from a Nexus repo 🙏

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

    As someone who was in the group of not knowing what move semantics are, I now feel like I understand them! Essentially, skip the copy constructor call, skip the temporary object creation and simply call the move constructor for increased performance. Set the old pointer to nullptr in the move constructor.

  • @bodguy1035
    @bodguy1035 Před 4 lety +9

    this talk is actually very good explanation about weird part of move semantics

  • @Gloryisfood
    @Gloryisfood Před 2 lety +6

    Best move semantics video I've ever seen!

  • @tourdesource
    @tourdesource Před rokem +2

    [46:15] "You don't really have to protect against move to self"
    Well, unless you're holding a pointer to a Widget. Then if you do w = std::move(*w.pw), you end up deleting the thing you're trying to move from, which is not exactly self-assignment but still dangerous. Arthur O'Dwyer explains this situation in his talk about RAII, also from CppCon 2019, and presents it as a justification for preferring the std::swap method.

  • @bobbymah2682
    @bobbymah2682 Před 4 lety +1

    Great talk! Cleared up details for me, thanks

  • @sezerbaglan1804
    @sezerbaglan1804 Před 4 lety +1

    The best explanation ever!

  • @christoj
    @christoj Před rokem

    Thank you, excellent talk, very easy to understand.

  • @SuhailKhan-vr6ik
    @SuhailKhan-vr6ik Před 4 lety

    Excellent talk!

  • @lwrcica5
    @lwrcica5 Před 4 lety

    Great presentation!

  • @marcospatton
    @marcospatton Před 2 lety

    Great talk !!! very clearned up details for me.

  • @dechencheng8847
    @dechencheng8847 Před 3 lety +1

    excellent talk!

  • @sushillakra21
    @sushillakra21 Před 2 lety +4

    Excellent talk, I came to learn new things which help me improve my own project! Thanks :)

  • @RaymondHulha
    @RaymondHulha Před 4 lety +2

    Super awesome Video! Thank you for sharing! Vielen Dank :)

  • @ivancheburan2209
    @ivancheburan2209 Před rokem +2

    According to core guidelines C.65 in the example of Widget's move assignment operator he should have added a simple check for self-reference, it would solve problem pointed out by a woman from the audience.

  • @joesilver75
    @joesilver75 Před 4 lety +3

    Thank you for using the uniform initialization.

    • @joesilver75
      @joesilver75 Před 4 lety

      ...but not in the member initializer list :-(

  • @codefool3022
    @codefool3022 Před 4 lety +4

    Small correction - @53:16 He mentions Core Guideline C.15. There is no C.15 (yet) - he meant F.15.

  • @manuelvalencia6705
    @manuelvalencia6705 Před 9 měsíci

    illuminating

  • @pmcgee003
    @pmcgee003 Před 4 lety +55

    The move operator is actually an eviction operator. :)
    I'm taking your house.

    • @francescocapano6732
      @francescocapano6732 Před 4 lety +18

      Seems more of a burglar operator to me.
      I'm taking everything from your house, you're welcome.

    • @CookiePepper
      @CookiePepper Před 2 lety

      It is just a title transfer instead of building the same house.

    • @Evan490BC
      @Evan490BC Před 2 lety

      It's more like "I am transforming my house into a caravan so that it can move". The std::move function is essentially a static_cast.

  • @Vermilicious
    @Vermilicious Před 4 lety +12

    Another reason to avoid raw pointers? I think so.

  • @kpopisthebestful
    @kpopisthebestful Před 4 lety +1

    But what if you had Widget as a data member and in the move assignment/copy, you do this->widget = std::move(Widget&& w);. Wouldnt this cause some infinite loop? In that case would i just have to do this->widget = w.widget and have no other choice but to use copy constructor?

  • @Stierguy1
    @Stierguy1 Před 4 lety +20

    I'm so sad that Klaus didn't mention that you can do std::move(w).i and std::move(w).s. The members of an rvalue are rvalues!

    • @sukraatahluwalia5137
      @sukraatahluwalia5137 Před 4 lety +1

      Wouldn't i(w.i) be not a move since int is a trivially copyable type, and move on such types is a no-op?

  • @player-eric
    @player-eric Před rokem

    By the way, how can I find the implementation of std::move like you did?

  • @sureshm8289
    @sureshm8289 Před 4 lety

    wow great video. and where can I get information about the coding guidelines which you were referring about?

  • @saichandu8178
    @saichandu8178 Před rokem

    one question I have is, how does a chained move assignment works?

  • @liveonphoenix5045
    @liveonphoenix5045 Před 2 lety

    @18:34, private var i, s, or pi. The default move-constructor or default assign move-operator, what will happens to the previous var/fields are they being reset like this? w.i = 0, w.s = NULL, w.pi = nullptr. Is this right?

  • @rahuldeshmukhpatil
    @rahuldeshmukhpatil Před 3 lety

    at 28:10, does he mean "If I do not make *move* constr noexpcet" ? he said "copy constr".

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

    I have a quick question. What happens if the previous variable is now empty? Even though it is empty, it retains a specific size and cannot become an external resource to other processes until it is no longer in scope.

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

      If we have dynamic memory, we can manually free it or reuse it for other purposes. However, in RAI Initialization, it will be freed as soon as the scope is finished.

  • @Antagon666
    @Antagon666 Před rokem

    I find tutorials on this topic very lacking. First time ever hearing about noexcept for example. Or the move constructors, where you have to call move anyways.
    I wonder if it's possible for standard to implement automatical moves where you don't need copy (passing temporary variables through series of const ref parameters in nested function calls for example).

  • @Lecker9419
    @Lecker9419 Před 3 lety

    At 45:32, can it be that the passed in object (w)'s destructor gets called while you
    are move-ing its fields and potentially move garbage to *this object?

    • @D0Samp
      @D0Samp Před 2 lety

      Not under normal conditions, since the object will not go out of scope as long as the move assignment operator holds a reference to it. An rvalue&& reference behaves the same as a lvalue& reference in that regard.

  • @Webfra14
    @Webfra14 Před 4 lety +1

    @51:47 - Why is there no point in move operations for virtual classes?

    • @ALX112358
      @ALX112358 Před 4 lety +7

      It would make sense only if both classes were of the same type.
      But what if you know only a common base class? It is either unsafe, or you need a dynamic cast with exception when dynamic cast fails. It is a troublesome situation no matter how you look at it.

  • @pralaypatoria1352
    @pralaypatoria1352 Před 2 lety

    Do we really need std::move(w.pi); ? pi=w.pi; should what we require ? eventually pi=std::move(w.pi) will do the same as its just a static cast and its relevant for class objects so that their move operators are called but not relevant for pointers. please correct me if wrong.
    delete pi; isn't incorrect? it should be delete[] pi;? assuming you used int* to allocate dynamic array?

  • @pedantic79
    @pedantic79 Před 4 lety +3

    53:21 that should be F.15 not C.15

  • @movaxbx656
    @movaxbx656 Před 2 lety

    Around minute 45, about the move to self problem. Using std::swap() wouldn't make it safe and the object invariant since the pointer wouldn't be deleted?

    • @dennydaydreamer
      @dennydaydreamer Před rokem

      By unsafe you probably mean that the original value in *pi is lost, and therefore you would prefer the swap implementation. I think Klaus's argument is that if you write w = std::move(w), then you are expressing the idea that you no longer care about the value in w, therefore it is okay to release the memory in pi and reset it to nullptr. Either approach is fine and he indeed say you need to make a decision based on what you want. He also points out that one caveat of the swap implementation is that the memory of the assigned to object is not immediately released, which I think is an important point to note because you are relying on a properly written constructor to do the work.

  • @raymondyoo5461
    @raymondyoo5461 Před 4 lety

    53:30
    why std::array is 'expensive' to move???

    • @dennisrkb
      @dennisrkb Před 4 lety +2

      because the only way to 'move' it is to copy it, it's a value type.

  • @Quuxplusone
    @Quuxplusone Před 4 lety +3

    Part 2 is here: czcams.com/video/pIzaZbKUw2s/video.html

  • @GeorgeTsiros
    @GeorgeTsiros Před 4 lety +3

    so many good things about this presentation (audio, voice, articulation, rhythm etc), it breaks my heart to say that without seeing how exactly the statements are compiled and how exactly the memory is managed under the hood, i can't follow it.

    • @TheLeontheking
      @TheLeontheking Před 4 lety +2

      Showing that would probably have left behind a good part of the audience...

  • @fredrikorderud
    @fredrikorderud Před 4 lety +4

    I usually prefer to call the destructor explicitly when implementing move assignment operators. That way, I avoid duplication of the resource cleanup code. However, this doesn't seem to be common practice. Are there any arguments (besides performance) against calling the destructor in move assignment operators?

    • @Stierguy1
      @Stierguy1 Před 4 lety +8

      According to the standard, the lifetime of an object ends when its destructor is called, and use after lifetime is UB. Roughly, incurring this kind of UB may lead to the compiler breaking your program. If you manually invoke the destructor for any object, you must construct a new object in that memory before you can re-use it; if that object is a stack object, you must do so using placement new, and you must do so before the destructor is automatically invoked (this is mandatory, the destructor must not be called after the end of the object's lifetime). If a move assignment operator manually invokes the destructor, it must immediately construct a new object at the this pointer using placement new.

    • @fredrikorderud
      @fredrikorderud Před 4 lety +1

      @Ted Thanks a lot for the explanation! Do you then agree that the following could serve as a canonical move-assignment implementation, disregarding performance and assuming that a noexcept move-constructor is available?
      TYPE& operator = (TYPE&& other) noexcept {
      TYPE::~TYPE();
      new(this) TYPE(std::move(other));
      return *this;
      }

    • @fredrikorderud
      @fredrikorderud Před 4 lety +1

      I've now moved an updated version of this question to stackoverflow.com/questions/58280104/canonical-c-assignment-operators that incorporates the feedback from @Ted.

  • @Dante3085
    @Dante3085 Před 4 lety

    ~ 16:20 Why does move take an rvalue reference "T&& t" if it is supposed to return an rvalue reference ?

    • @dennisrkb
      @dennisrkb Před 4 lety

      that's a universal reference which can bind to anything. check out Scott Meyers' book and talks..

    • @MUCplusplus
      @MUCplusplus Před 4 lety

      std:move() takes a forwarding reference, not an rvalue reference. Please see the second part of your talk, which covers forwarding references in detail.

  • @hubertbonnisseur-de-la-bat4858

    I don't get it, at which point s + s = s is valid ?

  • @HelloMisraji
    @HelloMisraji Před 2 lety +2

    Wouldn't the code of self-move assignment operator result in a dangling pointer?

    • @D0Samp
      @D0Samp Před 2 lety

      While the deleted pointer is indeed moved to itself, it also gets set to nullptr in the moved-from object at the end, leaving nothing behind.
      One advantage of std::swap over explicit nulling is that you get to keep the allocation in this case.

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

      @@D0Samp How does that answer the question? I was also wondering about a dangling pointer. If we assign to self, and delete the pointer in the beginning of the move assignment operator, then essentially the object that we're moving from (ourselves) would also have a pointer that points to nowhere, which we would try to move to our object, resulting in a dangling pointer. How does std::swap help here?

    • @rabingajmer3293
      @rabingajmer3293 Před rokem

      With the move assignment from the video, we will end up having a nullptr which is not transferring ownership at all. I think the presenter didn't understand the question that the woman asked properly.

  • @jamessilva8331
    @jamessilva8331 Před 4 lety

    Hey just wanted to add that the delete pi around the 40:00 minute mark would likely be a delete[ ] pi in practice because the pi was likely created with a new [ ].

  • @esra_erimez
    @esra_erimez Před 4 lety +22

    I have to say, that when a language needs an hour long two part video on basic functionality such as move, there is something fundamentally wrong with it.

    • @absurdengineering
      @absurdengineering Před 4 lety +5

      C++ is many languages in one, including C. The talk covers that - it can’t just presume that you will only use the modern parts and ignore all else.

    • @pedrov8868
      @pedrov8868 Před 2 lety +2

      Is it that basic though?

    • @b1ueocean
      @b1ueocean Před rokem

      It’s an absolutely horrible language - there is no doubt about that 🙂
      I’ve just mandated it as the primary development language at my startup, side-stepping go, rust, zig, carbon et al, so I must be absolutely horrible too 😂
      20+ years doing Java which has become horrible in different ways led me to take another look at C/C++… it’s a completely different beast to when I was doing game and graphics engines in Borland, Watcom, TASM and MASM back in the day.
      Windows API, MFC and COM programming using Hungarian syntax all of a sudden doesn’t seem that bad at all compared to this b.s. they are actually calling “modern”.
      A modern nightmare with jobs that don’t pay anywhere near enough to justify the cognitive (over)load and management/maintenance headaches.
      I’ve had 5 segfaults due to bad inputs this week, the last time I had a program crash out at runtime this way was 1999 🤷‍♂️
      Hello Again C++ World 💩

    • @iliasalaur
      @iliasalaur Před 8 měsíci +1

      well, what do you think why nobody uses JS for let’s say commercial embedded development? Some languages need to be hard, in order to endow the programmer with superpowers. But as it was said, with great power comes a greater responsibility

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

      Esra, I've seen you comments on other channels and I totally agree with you. The language has totally jumped the shark and gets worse with every standards release. I have a book that's over 200 pages that goes over how to use move semantics - just move semantics, that's all the book is about. I'm sorry but that's just absurd. I dunno maybe the language is this way so that more books on how to navigate the mess get sold.

  • @child_of_god_
    @child_of_god_ Před 3 lety +1

    i find this video hard to understand. a video by "the cherno" named "Move Semantics in C++" really kills it. it's down to earth

    • @shoulderstack5527
      @shoulderstack5527 Před 2 lety

      Yes, The Cherno is brilliant. All his C++ stuff is a god send.

    • @_Omni
      @_Omni Před rokem

      Its not hard 🤣