Live data from Hacker News

Move, simply

herbsutter.com

61–70 of 96 posts

Re: Move, simply

#61
post #17

C++ “move” semantics are simple, but they are still widely misunderstood. No, they aren't simple and the fact that are still widely misunderstood is basically proof of that. Maybe, just maybe, it has something to do with stuffing rvalue references, perfect forwarding and the whole universal-references-template-clusterfuck into one and the same syntax. [1] The default compiler-generated move can leave behind a null sp…

> No, they aren't simple and the fact that are still widely misunderstood is basically proof of that.

The article disproves itself. Sure, move is simple, if you stick to that one very narrow use case (that still needs std::move() boilerplate around moves to signal intent).

The problem (that the article then goes to point out) is that there are so many non-simple and buggy ways move can (and does) get used.

So you don't just need to learn the simple use case (with added boilerplate), you also need to learn all the complicated buggy use cases so that you can avoid using them.

For actual "simple" moves, try Rust.

Re: Move, simply

#62
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…

To me the question isn't a philosophical one, but a practical one. The more states an object has, the more special cases you have to handle, the more likely you are to get one wrong. The more methods an object has that can only be used when the object is in a particular state, the more likely the user of the class it to make a mistake.

Re: Move, simply

#63
post #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?

I think the reason for std::move is that the && function typically has a plain & counterpart (i.e. plain copy). Without std::move, the lvalue (named object) ends up calling that override.

Re: Move, simply

#64

I found it's much easier to understand the concepts behind move operations if you write an object that implemented move semantics by itself. class Object { int* data = new int[32]; void move_into( Object& object ) { object.data = data; data = nullptr; } ~Object() { delete[] data; } } Object a; Object b; a.move_into( b ); I think much of the confusion arises from wondering where is the allocation for int* data located…

Don't you have to destroy the target object, before you move into it?

Yes, this is a memory leak.

Re: Move, simply

#65
post #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?

&& doesn't mean "move here". It means, roughly speaking, "bind to things that are okay to implicitly move from, because they're going away anyway" (e.g. rvalues, or when you are returning a local).

std::move() is there to allow you to explicitly say, "this is okay to move from, even though it can still be accessed after the move".

Re: Move, simply

#66
post #48

"About the same time we were starting to work on Go, I read, or tried to read, the C++0x proposed standard and that was convincing to me." -- Ken Thompson Source -- https://www.youtube.com/watch?v=sln-gJaURzk

Go has it bad - the bread-and-butter append() may or may not alias the original array. Even C++ balks at non-deterministic aliasing.

Re: Move, simply

#67
It's 2020. We have planetary scale computers that do exaflop computations and AIs that can slaughter humans at almost any strategy game. The entire stock market is essentially driven by AI. Drugs are being developed by AI. Bitcoin is consuming more electricity than Ireland.

And yet programmers are still fucking around with move constructors, copy semantics, and host of other horseshit foisted upon us by people who think that saving a copy of a couple words of memory here and there should be absolutely foremost in programming. And then one of those designers has the gall to tell us we are all stupid for not understanding this and blowing our legs off every day.

C++ is such a waste of everyone's time. Don't even get me started on how much computational power its build system wastes.

sigh

Re: Move, simply

#68
post #43

Earlier quoted context omitted.

> It's going to be amazing when they add a true "destructive move" and everyone has to learn about the different kinds of moves and when to use which one. No different than when they added move the first time in C++11 and everybody had to learn the difference between copy and move. No different than Rust programmers learning the difference between Rust's move and C++'s move. Stuff changes over time. In this case, I t…

> No different than when they added move the first time in C++11 and everybody had to learn the difference between copy and move. Yes, it's not the first time the cognitive load of C++ has increased. > No different than Rust programmers learning the difference between Rust's move and C++'s move. Learning concepts in a new language doesn't increase cognitive load in the same way. In C++ you will have to decide which k…

Happily the undefined behavior plan for C++ seems to be, in addition to putting all the UB definitions in one place, requiring all new proposals justify why something should be UB or UD.

E.g. no more "it requires work to say what happens" UB cop outs - if something can be defined it should be.

In this case I'd say that a value cannot be used after it is destructively moved. There is no reason for that to be UB, when the language can just refuse to compile it.

Re: Move, simply

#69
post #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.

The compiler can just say "this value is dead, you can't use it".

That's what rust does - rust isn't literally freeing/clearing memory when a struct is moved.

Re: Move, simply

#70
post #62

Earlier quoted context omitted.

> 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…

To me the question isn't a philosophical one, but a practical one. The more states an object has, the more special cases you have to handle, the more likely you are to get one wrong. The more methods an object has that can only be used when the object is in a particular state, the more likely the user of the class it to make a mistake.

Sure, but states are just there, and acting like they weren't can even increase complexity. For example, RAII basically eliminates the "memory is allocated bit uninitialized" state by means of enforcing an automatic transition, at the cost of being no longer able to allocate many objects sratically.
Post reply on HN