5 ms·
>Apparently, after termination of show after the move, the object is invalidated. This does not affect the Person object, but only the string object. Recognize
by fluoridation 2y ago
>Apparently, after termination of show after the move, the object is invalidated. This does not affect the Person object, but only the string object. Recognize that I speak about a factual behavior on the hardware. I think we have undefined behavior here. And no compilation error.
The std::string is not invalidated, it's reset to its empty state (i.e. null pointer and zero length). Standard classes are all in defined, valid states after being moved, such that using them again is safe. User-defined classes may be coded to be left in either valid or invalid states after being moved. It's the responsibility of the programmer to decide which is appropriate according to the situation. There are valid reasons to want to reuse a moved object. For example, you might want to force the release an object's internal memory:
std::string() = std::move(s);
It's somewhat unfortunate that there's no way to signal to the compiler than an object is not safe for reuse, though.
- account42 2y agoWhile the language doesn't forbid use after move, occurences of it are most likely a programmer error. Which is why clang-tidy has the bugprone-use-after-move check.
- alkonaut 2y agoThis sounds like an enormous footgun (but as I understand it there are warnings that will tell you). An object isn't "valid" in any reasonable business logic sense just because the fields are initialized to anything at all, such as their default state? If the valid state of a Person is "the name is not empty " and this is enforced by a constructor then I don't want the program to ever have Person object floating around with a blank name? I either want a compiler error (good) or an immediate crash at runtime (bad), but at least I don't want an invalid object in a still running program (worse). Maybe I misunderstand what the reset was or how big this risk is though.
- fluoridation 2y ago>An object isn't "valid" in any reasonable business logic sense just because the fields are initialized to anything at all, such as their default state That very much depends on your use case. >If the valid state of a Person is "the name is not empty " and this is enforced by a constructor then I don't want the program to ever have Person object floating around with a blank name If you have such strict requirements then you shouldn't be moving around Persons to begin with. You should just be using std::make_unique() and then moving the pointer. Person should not even have a move constructor defined. If you code your class such that it's possible to let it reach an invalid state, that's no one's fault but your own.
- Joker_vD 2y agoEven if the std::string was guaranteed to hold a "SORRY, THIS STRING HAS BEEN MOVED FROM, PLEASE CONTACT YOUR LOCAL STRING SUPPLIER" string in it after being moved from, I doubt this would actually help that much with the overall correctness of the application. There are very, very few cases where it is "sensible" to do anything with such an "arbitrarily conjured" state except than disposing of/overwriting it. In fact, the only example I can vaguely remember of (and can't for the life of me to google) is that one scheme of storing some sort of lookup index in two arrays that store indices into each other, and it's not necessary to zero out those arrays before using them because the access algorithm is cleverly arranged in such a way that no matter what numbers are stored in the unused parts of the arrays, it will still work correctly.
- fluoridation 2y ago>Even if the std::string was guaranteed to hold a "SORRY, THIS STRING HAS BEEN MOVED FROM, PLEASE CONTACT YOUR LOCAL STRING SUPPLIER" string in it after being moved from That's a rather weak "even if", given most implementations just reset to the empty string after moving. >I doubt this would actually help that much with the overall correctness of the application. Like I said, it depends on your use case. A pattern I use frequently when processing input is to have an accumulator that I build up progressively, and then when ready I move it into a result container, and since that resets the accumulator I can simply keep using it. If my algorithm required the initial state "SORRY, THIS STRING HAS BEEN MOVED FROM, PLEASE CONTACT YOUR LOCAL STRING SUPPLIER" rather than the empty string, such an idiosyncratic post-move value would be rather convenient.
- alkonaut 2y ago> If you code your class such that it's possible to let it reach an invalid state, that's no one's fault but your own. I don't know C++ so I was given the impression in the article that the person writing the class could try very hard to make it impossible to reach an invalid state, but that this work could be ignored elsewhere by making a move of this kind which would work without any special requirements on the type itself.
- gpderetta 2y agoThe lack of so called destructive moves in C++ is not great. You either add a proper empty state to your type and make it properly part of the invariant, which is not always possible or meaningful, or you need a special moved from state for which your object invariant doesn't hold, which is "less than ideal" to say the least.
- quietbritishjim 2y ago> >Apparently, after termination of show after the move, the object is invalidated. This does not affect the Person object, but only the string object. Recognize that I speak about a factual behavior on the hardware. I think we have undefined behavior here. And no compilation error. You're right to pick up on this. The author of the article is confused here, or at least using incorrect terminology. There's certainly no "undefined behaviour" going on. But your corrections aren't quite right either, or at least use slightly odd definitions. > User-defined classes may be coded to be left in either valid or invalid states after being moved. No, even user defined classes have to be valid after a move, because their destructor will still be run. If you had your own vector-like class that points to invalid memory (or the same memory as the moved-to object) then you will get corruption when its destructor tries to free that memory. Ok, it's true that you could manually define an "invalid" state in your class, perhaps by adding an internal Boolean flag which you set when the object is moved from. Then you could throw an exception or abort or whatever when any method (except the destructor) is called with this flag set. But you'd have to go out of your way to do this and I've never seen it done. I don't think this is what most people would understand your statement to mean. > The std::string is not invalidated, it's reset to its empty state (i.e. null pointer and zero length). I'm not sure whether you're implying this is a strict requirement or just happens to be what happened in this case. In fact, the standard does not require this: the string could be left in any (valid, whatever that means) state. It could be empty, unchanged, or anything else. As other comments have noted, if the string's length is below the short string optimisation threshold then it's quite likely the original string will retain its value unchanged. Only a few specific types in the standard library have the guarantee that they will be empty after being moved from, and string isn't one of those.
- stonemetal12 2y ago>No, even user defined classes have to be valid after a move, because their destructor will still be run. So the compiler will complain and not compile your program?? Nope. It should be if you want a program that functions correctly, but have to? No, C++ doesn't force that on you.
- fluoridation 2y ago>No, even user defined classes have to be valid after a move, because their destructor will still be run. By "valid" I mean that you can use the object like normal; being able to destruct the object is not enough. If the destructor is unsafe to run (for example because the object ends up owning a dangling pointer) you just have an outright bug. An invalid state would be one where any further use of the object (other than destroying it) is an error. >I'm not sure whether you're implying this is a strict requirement or just happens to be what happened in this case. Yes, I'm saying that's what happened in that case. The string was not invalidated, it was reset.