6 ms·
I always understood move as moving ownership, so it's not a misnomer. > std::move is like putting a sign on your object “I’m done with this, you can take its s
by shmerl 9mo ago
I always understood move as moving ownership, so it's not a misnomer.
> std::move is like putting a sign on your object “I’m done with this, you can take its stuff.”
Which exactly is moving ownership.
- cocoto 9mo agoPersonally I see std::move more like removing ownership because it’s not explicit from its call where the ownership is transferred.
- tsimionescu 9mo agoEven that is a bit suspect, because ownership may well remain with you even after the call, so it's not really removed. For example, this is perfectly valid C++, and it is guaranteed to have no issue: std::string abc = "abc"; std::move(abc); //doesn't remove ownership or do anything really std::print(abc); //guaranteed to print "abc"
- vlovich123 9mo agoStd 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.
- shmerl 9mo agoMay be disown would be more descriptive, but the point is that it's intended for transferring of ownership versus copying data.
- masklinn 9mo 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.
- mgaunard 9mo agoThat'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 9mo agoWell 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
- tsimionescu 9mo agoIt 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 9mo agoMy function can choose to move or not to move from an object based on io input.
- tsimionescu 9mo agoCan 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.
- masklinn 9mo 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); } }
- tsimionescu 9mo agoThis is exactly what I meant as irrelevant. If I call `foo(std::move(my_unique_ptr))`, I know for sure, statically, that my_unique_ptr was moved from, as part of the function call process, and I can no longer access it. Whether `foo` chooses to further move from it is irrelevant.
- knorker 9mo agoAfter moving a value, it needs to remain in a "valid but unspecified state". How do you mean accessing a valid object is UB?
- drysine 9mo 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.movedfrom#1 https://timsong-cpp.github.io/cppwp/n4950/lib.types.movedfro...
- knorker 9mo agoOk, 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 9mo agoI 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.
- masklinn 9mo 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).
- tsimionescu 9mo agostd::move itself doesn't move ownership, though. It allows the compiler to transfer ownership to the receiver of the value, but it doesn't force it in any way. This is important, because it means YOU may still be the owner of a value even after you called std::move on it. Not to mention, ownership in C++ is not entirely lost with moves in the traditional sense. For example, your code still has to destruct the object even if you did move it to somewhere else.
- HarHarVeryFunny 9mo agoWell, no, because CAN take isn't the same as WILL take. Changing something to an rvalue means it'll now match a move constructor, but there is no guarantee a move constructor will be used, even if defined, because you've got classes like std::vector that are picky and are explicitly looking for a noexcept move constructor.
- fluoridation 9mo agoIn that sense, std::move() is no different than other passing semantics. Just because you wrote at the call site that you want to pass a copy of your object doesn't mean that the callee will actually make a copy of it.
- HarHarVeryFunny 9mo agoI'm not sure what you are saying. If we have foo(std::string a, std string b), and then call it like this: std::string x; std::string y; foo(std::move(x), y); Then x will be moved into a, and y will be copied into b. The callee has no say in this - it's just the compiler implementing the semantics of the language.
- fluoridation 9mo agoWho says there's only one resolution candidate? A different overload could be defined elsewhere that the compiler prefers for that particular combination of arguments, that doesn't cause a copy. std::move() works the same way. The semantics of the operation is defined not by what's at the call site, but by the context.
- HarHarVeryFunny 9mo agoSure overload resolution happens first, but once the compiler has found the correct match then the way arguments are passed depends only on the function signature of that match (callee), and how the caller is passing. An argument passed to a value parameter will be passed by copying, unless it's an rvalue (e.g. forced with std:move) where a move constructor has been defined for that type, in which case it will be moved. The callee has no say in this.
- usefulcat 9mo agostd::allow_move probably would have been a more accurate name for std::move.