Live data from Hacker News

Move, simply

herbsutter.com

51–60 of 96 posts

Re: Move, simply

#51
post #7

Earlier quoted context omitted.

Herb Sutter's article shows why this is actually a big problem in practice. He has an example of a class containing a guaranteed-non-null owning pointer. Leaving an object of this class in a "valid but unspecified state" means when you move out of it, you'll have to replace the internal pointer with a pointer to some new allocation, the very thing move semantics is supposed to help avoid. He suggests that such a clas…

Not quite. Let's suppose that I've got a pointer to a rather large array, and that array can't be null. When I move, the moved-from then has to allocate a new array, to satisfy the can't-be-null constraint. So I have the overhead of the allocation. But I don't have the overhead of copying all the bytes of the array.

>So I have the overhead of the allocation. But I don't have the overhead of copying all the bytes of the array.

The overhead of allocation is a magnitude greater evil than copying the bytes of the data structure the vast majority of the time. Most data is small and short lived. As well, copying bytes in memory doesn't have side effects and is far more deterministic than allocation.

The fact the spec says non trivially-copyable data must be in some "valid but unspecified" state means that move semantics in C++ are borderline useless, except in contrived cases like the one you present.

Re: Move, simply

#52
post #46

> (Other not-yet-standard proposals to go further in this direction include ones with names like “relocatable” and “destructive move,” but those aren’t standard yet so it’s premature to talk about them.) Herb Sutter seems to be burying the lede here. My read on Herb Sutter's post is that the current typical methodology (as represented by the IndirectInt example), is buggy as per the current specification. What we all…

So, what do you propose std::move should do? Initializing the ‘source’ int to zero seems the only reasonable option, but it would hurt performance. Also, what about std::move in general? If T has a destructor, should that call it on the original? Currently, deciding whether that (or doing its equivalent) is a good idea is up to the implementer of std::move . I don’t see how the compiler could make that decision witho…

>So, what do you propose std::move should do?

Just copy Rust. Trivially copyable types aren't invalidated by moves, and "move" just aliases copy.

Re: Move, simply

#53
post #46

Earlier quoted context omitted.

So, what do you propose std::move should do? Initializing the ‘source’ int to zero seems the only reasonable option, but it would hurt performance. Also, what about std::move in general? If T has a destructor, should that call it on the original? Currently, deciding whether that (or doing its equivalent) is a good idea is up to the implementer of std::move . I don’t see how the compiler could make that decision witho…

>So, what do you propose std::move should do? Just copy Rust. Trivially copyable types aren't invalidated by moves, and "move" just aliases copy.

Is the intention of std::move that the "moved-from" pointer no longer has its destructor run?

What if you move a unique_ptr from a std::vector? You don't know which elements of the vector need to have their destructors run.

I think Rust unconditionally doesn't run the destructor of a moved-from Box, but uses drop flags for "maybe-moved-from" local variables, and doesn't allow maybe-moved-from Vec elements.

Re: Move, simply

#54

Earlier quoted context omitted.

Not quite. Let's suppose that I've got a pointer to a rather large array, and that array can't be null. When I move, the moved-from then has to allocate a new array, to satisfy the can't-be-null constraint. So I have the overhead of the allocation. But I don't have the overhead of copying all the bytes of the array.

>So I have the overhead of the allocation. But I don't have the overhead of copying all the bytes of the array. The overhead of allocation is a magnitude greater evil than copying the bytes of the data structure the vast majority of the time. Most data is small and short lived. As well, copying bytes in memory doesn't have side effects and is far more deterministic than allocation. The fact the spec says non triviall…

Not quite. It's the "pointer cannot be null" requirement that makes it useless here. If you allow "pointer can be null for a moved-out-of object", then they're much more useful.

I'd say that it's the "pointer must not be null, even for a moved-out-of object" that's the "contrived" part.

Re: Move, simply

#55

This 20min Chrome Dev video goes over the same topic https://youtu.be/UNJrgsQXvCA

It's hilarious to me that the guy working on the Chrome performance optimization team and presumably a world-class C++ expert still has trouble with some questions about how the language semantics in certain cases. How do they expect normal people to use this language?

Re: Move, simply

#57
post #53

Earlier quoted context omitted.

>So, what do you propose std::move should do? Just copy Rust. Trivially copyable types aren't invalidated by moves, and "move" just aliases copy.

Is the intention of std::move that the "moved-from" pointer no longer has its destructor run? What if you move a unique_ptr from a std::vector? You don't know which elements of the vector need to have their destructors run. I think Rust unconditionally doesn't run the destructor of a moved-from Box, but uses drop flags for "maybe-moved-from" local variables, and doesn't allow maybe-moved-from Vec elements.

My point was on handling the moving of trivially copyable types, like int, not those with side effects like unique_ptr. For trivially copyable types, copy and move are (almost) synonymous, and can be made such in Rust with #[derive(Copy)].

But that difference actually gets to your point here. The only difference between copy and move is that a move allows for the new data to overlap the previous. So if you think about what moving from a vector of unique ptr actually means, it must invalidate the vector or remove the element that was moved from the vector. If you want to get the element from the vector without those effects, you have to create a deep copy.

Basically moving without invalidating or mutating such that the moved-from alias can no longer be accessed is necessary.

Re: Move, simply

#58

> (Other not-yet-standard proposals to go further in this direction include ones with names like “relocatable” and “destructive move,” but those aren’t standard yet so it’s premature to talk about them.) Herb Sutter seems to be burying the lede here. My read on Herb Sutter's post is that the current typical methodology (as represented by the IndirectInt example), is buggy as per the current specification. What we all…

Destructive move would be incompatible with c++ as it works today. If you construct an object it’s valid. Since move doesn’t do delete() (how could it?) it leaves behind a block of memory that the program considers an X and so must be valid.

Re: Move, simply

#59
post #9

Huh, I'm sure he is correct on the intent of the spec, but it is certainly not how our team has been interpreting the allowable state of objects after a move. And while I understand where he is coming from in always wanting the object to meet its invariants until it is destructed, I think this approach will make code harder to reason about rather than easier. I'm a huge proponent that classes should be fully configur…

> I really dislike classes that are only partially configured on construction, and then you have to call other methods to complete their initialization. What is "partially configured" after all? IMHO this dichotomy is just a headache brought to you by yours truly, OOP (or rather, syntactically enforced OOP ). Personally I don't want to spend the rest of my life pondering such philosophical questions. Or dealing with…

C++ doesn’t believe in “partially constructed”. The real world sometime has this unfortunate event but your code is supposed to deal with it.

Re: Move, simply

#60
Why is an explicit std::move required to pass a named object a as an argument to a && ? Shouldn’t the function’s signature tell the compiler that move is required?
Post reply on HN