Live data from Hacker News

The repercussions of missing an Ampersand in C++ and Rust

nablag.com

101–110 of 128 posts

Re: The repercussions of missing an Ampersand in C++ and Rust

#101
post #77

Earlier quoted context omitted.

By adding syntax and semantics for destructible moves, meaning the moved object is removed from its scope (without calling its destructor.)

I've worked with C++ for a number of years, with a few codebases that were >1M LoC. Never did I stumbled upon a situation where an object was moved and an existing symbol became a problem. I wonder what you are doing to get yourself in that situation.

> I wonder what you are doing to get yourself in that situation.

The problem with the current move semantics is that, compared to e.g. Rust: 1) the compiler generates unnecessary code and 2) instead of just implementing class T you must implement a kind of optional.

Which means, that after all those years of using smart pointers I find myself ditching them in favor of plain pointers like we did in the 90's.

Re: The repercussions of missing an Ampersand in C++ and Rust

#102
post #101

Earlier quoted context omitted.

I've worked with C++ for a number of years, with a few codebases that were >1M LoC. Never did I stumbled upon a situation where an object was moved and an existing symbol became a problem. I wonder what you are doing to get yourself in that situation.

> I wonder what you are doing to get yourself in that situation. The problem with the current move semantics is that, compared to e.g. Rust: 1) the compiler generates unnecessary code and 2) instead of just implementing class T you must implement a kind of optional . Which means, that after all those years of using smart pointers I find myself ditching them in favor of plain pointers like we did in the 90's.

When you say you must, do you mean that it’s best practice, that or that this is UB or similar?

Re: The repercussions of missing an Ampersand in C++ and Rust

#103
post #89

Earlier quoted context omitted.

Reopen by constructing and assigning a new socket.

So I essentially have to wrap it in something like std::optional. Well, that's certainly one way to write a socket class, but I'd say it's not idiomatic C++. (I have never seen a socket class being implemented like that.)

You don't need optional in this case, the assignment would just destroy the old socket and immediately move the new one in its place.

Re: The repercussions of missing an Ampersand in C++ and Rust

#104
post #91

Earlier quoted context omitted.

> And what's the underlying value of such a default constructed socket? I assume it would be -1 resp. INVALID_SOCKET No, as explained, the default value would be the result of `::socket` call, i.e. a fresh OS-level socket. > So you essentially must wrap it in an optional if you want to use it as a member variable. No, you only must wrap it if you really want this closed state to exist. > Sure, you can implement a soc…

> If they were, this design would be superior. I see how destructive moves would slightly simplify the implementation, but what difference would it make apart from that? (Don't get me wrong, I totally think that destructive moves are a good idea in general, I just don't see the qualitative difference in this particular case.) > And the wasted space for optional is solvable, just like for non-nullable pointers. In the…

> what difference would it make

The same difference as making pointers always non-nullable and reintroducing nullability via an optional wrapper only when semantically appropriate.

> what could you possibly do with an arbitrary user-defined class

Just add some customization points to std::optional so that users can define which value of the class to treat as noneopt internally.

Re: The repercussions of missing an Ampersand in C++ and Rust

#105
post #101

Earlier quoted context omitted.

I've worked with C++ for a number of years, with a few codebases that were >1M LoC. Never did I stumbled upon a situation where an object was moved and an existing symbol became a problem. I wonder what you are doing to get yourself in that situation.

> I wonder what you are doing to get yourself in that situation. The problem with the current move semantics is that, compared to e.g. Rust: 1) the compiler generates unnecessary code and 2) instead of just implementing class T you must implement a kind of optional . Which means, that after all those years of using smart pointers I find myself ditching them in favor of plain pointers like we did in the 90's.

> The problem with the current move semantics is that, compared to e.g. Rust: 1) the compiler generates unnecessary code and 2) instead of just implementing class T you must implement a kind of optional.

I don't know what you mean by "compiler generates unnecessary code" or why you see that as a problem. I also have no idea what you mean by "a kind of optional". The only requirement on moved-from objects is that they must be left in a valid state. Why do you see that as a problem?

Re: The repercussions of missing an Ampersand in C++ and Rust

#106
post #101

Earlier quoted context omitted.

> I wonder what you are doing to get yourself in that situation. The problem with the current move semantics is that, compared to e.g. Rust: 1) the compiler generates unnecessary code and 2) instead of just implementing class T you must implement a kind of optional . Which means, that after all those years of using smart pointers I find myself ditching them in favor of plain pointers like we did in the 90's.

When you say you must, do you mean that it’s best practice, that or that this is UB or similar?

> When you say you must, do you mean that it’s best practice, that or that this is UB or similar?

I'm not OP, but the only requirements that C++ imposed on moved-from objects is that they remain valid objects. Meaning, they can be safely destroyed or reused by reassigning or even moving other objects into them. I have no idea what OP could be possibly referring to.

Re: The repercussions of missing an Ampersand in C++ and Rust

#107
post #4

Rust's behavior of moving without leaving a moved-out shell behind also simplifies the implementation of the type itself, because its dtor doesn't have to handle the special case of a moved-out shell, and the type doesn't even need to be able to represent a moved-out shell. For example, a moved-out-from tree in C++ could represent this by having its inner root pointer be nullptr, and then its dtor would have to check…

This was one of the most unsatisfying things about learning C++ move semantics. They only kinda move the thing, leaving this shell behind is a nightmare.

> This was one of the most unsatisfying things about learning C++ move semantics. They only kinda move the thing, leaving this shell behind is a nightmare.

I don't know what nightmares you have. The only requirement that C++ specifies for moved-from objects is that they remain valid. Meaning, they can be safely destroyed.

You can go way out of your way and reuse an object that was just moved, but that's a decision you somehow made, and you have the responsibility of adding your reinitialization or even move logic to get that object back in shape. That is hardly something that sneaks up on you.

Re: The repercussions of missing an Ampersand in C++ and Rust

#108

Earlier quoted context omitted.

This was one of the most unsatisfying things about learning C++ move semantics. They only kinda move the thing, leaving this shell behind is a nightmare.

C++ doesn't have ownership baked into the language like Rust does, and "move semantics" is all about ownership (under the hood it's just a plain old shallow copy both in C++ and Rust). Making the moved from object inaccessible like in Rust would have required static ownership tracking which I guess the C++ committee was afraid to commit to (and once you have that, you're basically halfway to Rust, including the downs…

> Making the moved from object inaccessible like in Rust would have required static ownership tracking which I guess the C++ committee was afraid to commit to (...)

I'm not sure the "afraid to commit to" is a valid interpretation. The requirements that the C++ standard specifies for moved-from objects turns that hypothetical issue into a non-problem. In C++, if you move an object then after the move the object must be left in a valid state. That's it. This means the object can be safely destroyed.

You are also free to implement whatever semantics your moved-from object has. If you want your moved-from object to throw an exception, you are free to implement that. If instead you want to ensure your moved-from can be reused you are also free to do so. If you want to support zombie objects then nothing prevents you from going that path. It's up to you. The only thing the standard specifies is that once the lifetime of that object ends, it can be safely destroyed. That sounds both obvious and elegant, don't you agree?

Re: The repercussions of missing an Ampersand in C++ and Rust

#109
post #38

Earlier quoted context omitted.

This was one of the most unsatisfying things about learning C++ move semantics. They only kinda move the thing, leaving this shell behind is a nightmare.

Since I use move semantics all the time, this is for me the most frustrating thing about C++ full stop. I really wish they'd fix this instead of adding all those compile-time features.

> Since I use move semantics all the time (...)

Everyone who ever uses C++ uses move semantics all the time,including move elision. It's not an obscure feature.

> (...) this is for me the most frustrating thing about C++ full stop.

I've been using C++ for years and I have no idea what you could be possibly referring to. The hardest aspect of move semantics is basically the rule of 5. From that point, when you write a class you have the responsibility to specify how you want your class to be moved and how you want your moved-from class to look like, provided that you ensure you leave it in a valid state.

That's it.

What exactly do you believe needs fixing?

Re: The repercussions of missing an Ampersand in C++ and Rust

#110

Earlier quoted context omitted.

This was one of the most unsatisfying things about learning C++ move semantics. They only kinda move the thing, leaving this shell behind is a nightmare.

When I looked into the history of the C++ move (which after all didn't even exist in C++ 98 when the language was first standardized) I discovered that in fact they knew nobody wants this semantic. The proposal paper doesn't even try to hide that what programmers want is the destructive move (the thing Rust has) but it argues that was too hard to do with the existing C++ design so... The more unfortunate, perhaps dis…

[deleted]
Post reply on HN