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

Поделиться
HTML-код
  • Опубликовано: 4 ноя 2024

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

  • @norikazuoshiro6324
    @norikazuoshiro6324 5 лет назад +135

    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 4 года назад +18

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

    • @masheroz
      @masheroz 2 года назад

      This one? ruclips.net/video/7Qgd9B1KuMQ/видео.html

    • @atib1980
      @atib1980 2 года назад +2

      @@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 Год назад

      @@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 🙏

  • @sky_is_the_limit_13
    @sky_is_the_limit_13 2 месяца назад +1

    He is truly a legend and one of my role models in the C++ world! Thanks CppCon for 'back to basics' idea and for uploading videos here for free!

  • @Gloryisfood
    @Gloryisfood 2 года назад +8

    Best move semantics video I've ever seen!

  • @mathymathhandle
    @mathymathhandle 3 года назад +6

    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 4 года назад +10

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

  • @codefool3022
    @codefool3022 4 года назад +6

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

  • @sushillakra21
    @sushillakra21 3 года назад +5

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

    • @CppCon
      @CppCon  3 года назад +3

      Great to hear!

  • @Stierguy1
    @Stierguy1 5 лет назад +21

    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 4 года назад +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?

  • @Vermilicious
    @Vermilicious 4 года назад +12

    Another reason to avoid raw pointers? I think so.

  • @ivancheburan2209
    @ivancheburan2209 Год назад +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.

  • @kaus05
    @kaus05 20 дней назад +1

    What does it mean by non owning pointer?

  • @pmcgee003
    @pmcgee003 5 лет назад +56

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

    • @francescocapano6732
      @francescocapano6732 5 лет назад +19

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

    • @CookiePepper
      @CookiePepper 3 года назад

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

    • @Evan490BC
      @Evan490BC 3 года назад

      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.

  • @tourdesource
    @tourdesource Год назад +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.

  • @joesilver75
    @joesilver75 4 года назад +3

    Thank you for using the uniform initialization.

    • @joesilver75
      @joesilver75 4 года назад

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

  • @sezerbaglan1804
    @sezerbaglan1804 4 года назад +2

    The best explanation ever!

  • @GeorgeTsiros
    @GeorgeTsiros 5 лет назад +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 4 года назад +2

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

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

    Thank you, excellent talk, very easy to understand.

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

    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).

  • @kpopisthebestful
    @kpopisthebestful 4 года назад +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?

  • @bobbymah2682
    @bobbymah2682 4 года назад +1

    Great talk! Cleared up details for me, thanks

  • @dechencheng8847
    @dechencheng8847 3 года назад +1

    excellent talk!

  • @pralaypatoria1352
    @pralaypatoria1352 2 года назад

    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?

  • @marcospatton
    @marcospatton 2 года назад

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

  • @liveonphoenix5045
    @liveonphoenix5045 2 года назад

    @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?

  • @RaymondHulha
    @RaymondHulha 5 лет назад +2

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

  • @pedantic79
    @pedantic79 4 года назад +3

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

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

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

  • @SuhailKhan-vr6ik
    @SuhailKhan-vr6ik 4 года назад

    Excellent talk!

  • @fredrikorderud
    @fredrikorderud 5 лет назад +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 5 лет назад +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 5 лет назад +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 5 лет назад +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.

  • @HelloMisraji
    @HelloMisraji 2 года назад +2

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

    • @D0Samp
      @D0Samp 2 года назад

      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 2 года назад +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 Год назад

      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.

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

    illuminating

  • @lwrcica5
    @lwrcica5 4 года назад

    Great presentation!

  • @Quuxplusone
    @Quuxplusone 5 лет назад +5

    Part 2 is here: ruclips.net/video/pIzaZbKUw2s/видео.html

  • @liveonphoenix5045
    @liveonphoenix5045 2 года назад +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 2 года назад +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.

  • @rahuldeshmukhpatil
    @rahuldeshmukhpatil 3 года назад

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

  • @player-eric
    @player-eric Год назад

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

  • @movaxbx656
    @movaxbx656 2 года назад

    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 Год назад

      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.

  • @thestarinthesky_
    @thestarinthesky_ 2 месяца назад

    @19:23 does anyone know what he meant when he said "as soon as you leave out any reference, it would be the copy constructor or the copy assignment operator"?

    • @kaus05
      @kaus05 20 дней назад

      If you leave an ampersand than it would call the copy constructor instead of move

  • @sureshm8289
    @sureshm8289 4 года назад

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

  • @Lecker9419
    @Lecker9419 4 года назад

    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 2 года назад

      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.

  • @jamessilva8331
    @jamessilva8331 4 года назад

    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 [ ].

  • @Webfra14
    @Webfra14 5 лет назад +1

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

    • @ALX112358
      @ALX112358 5 лет назад +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.

  • @hubertbonnisseur-de-la-bat4858

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

  • @raymondyoo5461
    @raymondyoo5461 4 года назад

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

    • @dennisrkb
      @dennisrkb 4 года назад +2

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

  • @Dante3085
    @Dante3085 4 года назад

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

    • @dennisrkb
      @dennisrkb 4 года назад

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

    • @MUCplusplus
      @MUCplusplus 4 года назад

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

  • @esra_erimez
    @esra_erimez 4 года назад +23

    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 4 года назад +6

      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 2 года назад +3

      Is it that basic though?

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

      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 Год назад +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 10 месяцев назад

      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_ 3 года назад +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 2 года назад

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

    • @_Omni
      @_Omni 2 года назад

      Its not hard 🤣