Comment by vlovich123

Comment by vlovich123 17 hours ago

33 replies

Std move doesn’t move ownership. It simply casts into something that could have its ownership taken. Whether or not that actually happens is impossible to identify statically and the value after ownership is consumed is unspecified - sometimes it’s UB to access the value again, sometimes it’s not.

mgaunard 17 hours ago

That's quite inaccurate.

It needs to remain destructible, and if the type satisfies things like (move-)assignable/copyable, those still need to work as well.

For boxed types, it's likely to set them into some null state, in which case dereferencing them might be ill-formed, but it's a state that is valid for those types anyway.

  • vlovich123 11 hours ago

    Well it’s unspecified what empty/size return for collections after a move. Not a dereference, not UB but unspecified as I said. UB pops up in hand written code - I’ve seen it and the language doesn’t provide any protection here.

    Thankfully clippy lints do exist here to help if you integrate that tooling

shmerl 17 hours ago

May be disown would be more descriptive, but the point is that it's intended for transferring of ownership versus copying data.

  • masklinn 16 hours ago

    > it's intended for transferring of ownership versus copying data.

    It's intended for transferring ownership, but what it actually does is mark the value as transferrable, whether or not the value is actually transferred is up to the callee.

knorker 15 hours ago

After moving a value, it needs to remain in a "valid but unspecified state".

How do you mean accessing a valid object is UB?

  • masklinn 13 hours ago

    "Validity" is an extremely low bar in C++, it just means operations with no preconditions are legal, which in the most general case may be limited to destruction (because non-destructive moves means destruction must always be possible).

  • drysine 14 hours ago

    >After moving a value, it needs to remain in a "valid but unspecified state".

    No, it doesn't.

    The standard library requires that for its classes, but not the language.

    "Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state."[0]

    [0] https://timsong-cpp.github.io/cppwp/n4950/lib.types.movedfro...

    • knorker 13 hours ago

      Ok, fair enough.

      So you're saying if you use the language to write UB, then you get UB?

      Seems kinda circular. Ok, you're not the same user who said it can be UB. But what does it then mean to same "sometimes it's UB" if the code is all on the user side?

      "Sometimes code is UB" goes for all user written code.

      • drysine 12 hours ago

        I mean the language doesn't dictate what post-condition your class has for move-ctor or move-assignment.

        It could be

        - "don't touch this object after move" (and it's UB if you do) or

        - "after move the object is in valid but unspecified state" (and you can safely call only a method without precondition) or

        - "after move the object is in certain state"

        - or even crazy "make sure the object doesn't get destroyed after move" (it's UB if you call delete after move or the object was created on the stack and moved from).

        But of course it's a good practice to mimic the standard library's contract, first of all for the sake of uniformity.

tsimionescu 16 hours ago

It is absolutely knowable statically if ownership will be taken. It's not necessarily very easy to do so, but the decision is 100% up to the compiler, as part of overload resolution and optimization choices (like the NRVO analysis that the article mentions). Since ownership is an inherently static concept, it doesn't even make sense to think about "runtime ownership".

  • adrianN 16 hours ago

    My function can choose to move or not to move from an object based on io input.

    • tsimionescu 16 hours ago

      Can you show an example of what you mean?

      My claim is that, if I call `foo(std::move(myObj))`, it is statically knowable if `foo` receives a copy of `myObj` or whether it is moved to it. Of course, `foo` can choose to further copy or move the data it receives, but it can't choose later on if it's copied or not.

      Now, if I give `foo` a pointer to myObj, it could of course choose to copy or move from it later and based on runtime info - but this is not the discussion we are having, and `std::move` is not involved from my side at all.

      • ben-schaaf 13 hours ago

        No, it is not statically knowable if it is actually moved.

            void foo(Obj && arg) {}
        
        Does not move `arg`. It's fairly easy to write code that assumes `std::move` moves the value, but that can lead to bugs. For example:

            void some_function(std::vector<int> &&);
            void some_function2(std::vector<int> &&);
        
            void main() {
                std::vector<int> a = { 1 };
                some_function(std::move(a));
        
                a.push_back(2);
                some_other_function(std::move(a));
            }
        
        The expectation is that `some_other_function` is always called with `{ 2 }`, but this will only happen if `some_function` actually moves `a`.
        • adrianN 8 hours ago

          Is pushing to a moved-from vector even legal? I thought in general the only guarantee you have after a move is that is save to destruct the object.

      • masklinn 16 hours ago

        > Can you show an example of what you mean?

            void foo(std::unique_ptr<int, Deleter>&& p) {
                std::random_device rdev {};
                auto dist = std::uniform_int_distribution<>(0, 1);
                if (dist(rdev)) {
                    auto pp = std::move(p);
                }
            }
  • charcircuit 14 hours ago

    I don't understand the downvoted here. Either the compiler emits the code to call a move constructor or it doesn't.

    • Maxatar 13 hours ago

      Static analysis is about proving whether the code emitted by a compiler is actually called at runtime. It's not simply about the presence of that code.

      Code can be emitted but never executed.

      • charcircuit 5 hours ago

        >Static analysis is about proving whether the code emitted by a compiler is actually called at runtime.

        That is but one thing that can static analysis can prove. It can also prove whether source code will call a move contractor or a copy constructor. Static analysis is about analyzing a program without actually running it. Analysizing what code is emitted is one way a program can be analyzed.