C++ Weekly - Ep 452 - The Confusing Way Moves Can Be Broken in C++

Поділитися
Вставка
  • Опубліковано 24 гру 2024

КОМЕНТАРІ • 23

  • @cppweekly
    @cppweekly  Місяць тому +6

    Do you have any questions about CLion? Ask the team! They will host a special Q&A session on r/cpp from 1:00-5:00 pm CET on October 29, 2024. If you are curious about the 2024.2 release, 2024.3 roadmap, CLion Nova, or anything else - don’t miss your chance!
    jb.gg/cl_ama_2024

  • @stanbarvinsky1011
    @stanbarvinsky1011 Місяць тому +2

    Knew it already, and it was confusing at first. But it kind of forces you to follow „if you define a custom destructor, you need to define all other special functions“

  • @AlfredoCorrea
    @AlfredoCorrea Місяць тому +3

    2:33 In many cases it is enough to know if is_nothrow_move_constructible. This might be better than relying on a type to have move constructor specifically.

  • @KX36
    @KX36 Місяць тому +9

    I knew this already.. but my question is why is it so. As in, why in the standard does defining one special member function implicitly change all the other special member functions? Is that something that a committee decided on or a technical necessity and if it was a decision, what's the reasoning?
    I ask because it's a mistake I see again and again and it seems to be an unnecessary footgun in the language.
    I have heard the answer "well, if you want to be defining your own destructor, then any guess the compiler might make about how you want to handle the lifetimes, copies and moves of members could be wrong, and you've told the compiler that you really care about micromanaging all of that for all of the members, so you just have to define all of that yourself" but it doesn't sit well with me because surely there's a better answer than just secretly "nope" all the other special member functions.

    • @Jack-lh6gp
      @Jack-lh6gp Місяць тому +20

      from stackoverflow :
      The rationale behind this rule was that if your code has a custom destructor, it's probably because a resource needs to be freed; and if a resource needs to be freed then the default implementation of move may leave the source object in a bogus state.

    • @err6910
      @err6910 Місяць тому +8

      I'm pretty sure it was done for backward compatibilty with pre c++11 code. You did not have move semantics, and you do not want your legacy classes to suddenly have a (probably wrong) default move constrcutor/operator=.

    • @anon_y_mousse
      @anon_y_mousse Місяць тому

      @@Jack-lh6gp The reason that rationale doesn't sit well with me is because moving an object shouldn't involve calling a destructor or constructor. The whole point, or so I thought, is to optimize those operations away, basically to refer to an object in memory by another name. In essence, I would expect using `move` to be like assigning a pointer and involve calling no actual function. I suspect C++ does it in a way that's contrary to what I expect because of issues involving code generation of calls to destructors that automatically get inserted when an object's lifetime has ended, but I like my solution better even if it does involve writing more cases for code generation into the compiler.

    • @Spielix
      @Spielix Місяць тому

      @anon_y_mousse The problem isn't the move itself but what happens when the moved-from object's lifetime ends (i.e. what should the compiler do there by default). If there has to be a custom destructor, in many cases it's behavior has to depend on if the object has been moved from or not, but not in all (e.g. because freeing a nullptr is fine). In some cases one only had to add the move constructor while in others on has to change the destructor as well for nove semantics to work. The standard took the route with backward compatibility + complete flexibility for developers to decide how to handle the being-moved-from state of an object.

    • @anon_y_mousse
      @anon_y_mousse Місяць тому

      @@Spielix Tell me you didn't read my entire post without telling me.

  • @TheNovakon
    @TheNovakon Місяць тому +2

    The only problem is that is_move_constructible is not what people expect. Other aspects are logical. By defining destructor, the move constructor and assignment are disabled by default for compatibility reasons. You need always define own version of move constructor if you need to benefit from moving,

  • @entusiast2000
    @entusiast2000 Місяць тому +2

    Rule of 0 is good until you need to parametrize the construction. How often the default init is enough outside the laboratory?

    • @Wimpielef
      @Wimpielef Місяць тому

      Rule of 0 is not about the constructor, only about copy/move/assignment/destructor

    • @entusiast2000
      @entusiast2000 Місяць тому +1

      @@Wimpielef I mean that Rule of 0 is "you personally write zero constructors/destructors/assigns, because they may be autogenerated if needed". But if only you write any other c-tor or d-tor, this does not happen (at least always had been). And copy/move c-tors are also constructors. And of course you need couples of respective c-tor/assign. Of course, you may skip any of: default c-tor, copy c-tor, move c-tor. But if you have copy or move c-tor, please write the respective assign operator(s).

  • @besworland
    @besworland Місяць тому +2

    What about marking move constructor with noexcept? It might also end up with interesting behavior.

    • @AlfredoCorrea
      @AlfredoCorrea Місяць тому +2

      If you do that consistently (and you should) then it can be reliably detected with is_nothrow_move_constructible as I say in the other comment.

    • @besworland
      @besworland Місяць тому +2

      @@AlfredoCorrea agree, my point was more about that it can break move semantics and this point is worth to mention.

    • @AlfredoCorrea
      @AlfredoCorrea Місяць тому +3

      @@besworland Oh, I see. sorry, I didn't read it as a rhetorical question, :) yes, he should make the move constructor noexcept and then detect for noexcept. needing to detect for move constructor specifically is a code smell IMO. starting from the fact that built-in and legacy classes do no have a move constructor but might have a “safe enough” copy constructor.

  • @stephenhowe4107
    @stephenhowe4107 Місяць тому +3

    I know Howard Hinnant's table, Nevertheless the rules are confusing

  • @lx2222x
    @lx2222x Місяць тому

    I wish they fixed header units :/