7 ms·
Isn't the example with re-using a moved c++ vector completely safe? std::vector<int> x = {1, 2, 3}; process(std::move(x)); x.push_back(4); // R
by foota 8y ago
Isn't the example with re-using a moved c++ vector completely safe?
std::vector<int> x = {1, 2, 3};
process(std::move(x));
x.push_back(4);
// Runtime invalid memory access
- millstone 8y agoYes it is safe.
- kkimdev 8y agoOh, I didn't know about this one. I did some search, and looks like it should be "valid but unspecified state" after move? I can't think of any case that relying on unspecified state is desirable even if it's valid, though I guess it's better if I change that to x.pop_back(); to be clear. Please let me know if my understanding is incorrect and thanks for the information!
- lmitchell 8y agoThe only thing 'unspecified' guarantees you in this context is 'safe to destroy'. It specifically does not guarantee the safety of any other member functions - only the destructor. So either push_back() or pop_back() could potentially cause UB here (specifically, it's quite possible that the move swaps some internal pointers for nullptr, so you end up dereferencing null here - but morally, it's just never okay to continue using a moved-from object).
- millstone 8y agoThe vector is "valid" and that is what carries all the weight here. The vector is still a vector. push_back is absolutely defined. pop_back might be undefined, because pop_back is UB on an empty vector. If you like, call clear, and be assured of an empty, reusable vector. It's not idiomatic, but it's safe.
- pbsd 8y agoA moved-from std::vector<int> will always be empty. However, a moved-from std::vector<int, custom_stateful_allocator> may not be. Howard Hinnant had a Stack Overflow reply a while back going through the possible corner cases of this precise question: https://stackoverflow.com/a/17735913 https://stackoverflow.com/a/17735913
- bluejekyll 8y agoIt’s runtime safe (I’m taking your word for it). In Rust this would be a compile time error. Although, are any C++ compilers able to at least issue a warning in this case? It wouldn’t surprise me if they could.
- marcianx 8y agoYes, it's completely safe and its rust equivalent is let x = vec![1, 2, 3]; process(std::mem::replace(&mut x, Vec::new())); x.push(4); https://doc.rust-lang.org/std/mem/fn.replace.html https://doc.rust-lang.org/std/mem/fn.replace.html
- khuey 8y agoThere's no guarantee that std::move moves elements out of x. (and thus no guarantee that it's equivalent to a Rust mem::replace with a new Vec) The only requirement the C++ standard imposes is that the vector is left in a "valid but unspecified state".
- zelly 8y agoMove constructors are allowed to call the moved object's destructor. Not necessarily like the example given, but Object a {std::move(x)}; x.push_back(4); could/should segfault.
- ncmncm 8y agoNo, move constructors are never allowed to call the moved-from argument's destructor. Ever. Sometimes the compiler calls that destructor after it has finished the move, if the thing is no longer in scope. That should not be confused with a thing happening in the constructor.