C++ std::move doesn't move anything: A deep dive into Value Categories
111–120 of 220 posts
Re: C++ std::move doesn't move anything: A deep dive into Value Categories
#112Earlier quoted context omitted.
I hear this a lot, but I don’t really understand how this manifests in language complexity like the stuff in TFA in practice. Like, I can understand how systems programming requiring programmers to think about questions like “how can I proceed if allocation fails? How does this code work in an embedded context with no heap?” is hard and irreducible. But I can’t understand why a language’s choice to impose complex rul…
The difference is that in C one is supposed to do allocations and deallocations oneself. Then move semantics is just pointer assignment with, of course, the catch that one should make sure one does not do a double-free because ownership is implicit. In C++ ownership is indicated by types so one has to write more stuff to indicate the ownership.
No, you should only use the heap if necessary.
The bigger issue in C is there is no concept of references, so if you want to modify memory, the only recourse is return-by-value or a pointer. Usually you see the latter, before return value optimization it was considered a waste of cycles to copy structs.
In the embedded world, its often the case you won't see a single malloc/free anywhere. Because sizes of inputs were often fixed and known at compile time for a particular configuration.
Re: C++ std::move doesn't move anything: A deep dive into Value Categories
#113Earlier quoted context omitted.
A bit more if we consider the "bugfixing" release that was C++14 :) But yeah it makes sense, given how that was the jumpstart of the whole modernization of the language. I believe it was a big undertake that required the time it took. Still years have passed and footguns keep accumulating... it wouldn't hurt to have a mechanism to optionally drop the old cruft from the language. Otherwise everything stacks on top in…
While I share the sentiment, compare C#14 with C# 1.0, Java 25 with Java 1.0, Python 3.14 with Python 1.0. While C++ might be worse, when you have 300+ doing proposals every three years, others aren't safer from similar churn, even if on smaller volume, and trying to keep backwards compatibility going. And we all know what happened in Python. Also Rust editions contrary to what many think, only cover a specific set o…
This is a weird call-out because it's both completely incorrect and completely irrelevant to the larger point.
Rust absolutely supports binary libraries. The only way to use a rust library with the current rust compiler is to first compile it to a binary format and then link to it.
More so than C++ where header files (and thus generics via templates) are textual.
Cargo, the most common build system for rust, insists on compiling every library itself (with narrow exceptions - that include for instance the precompiled standard library that is used by just about everyone). That's just a design choice of cargo, not the language.
Re: C++ std::move doesn't move anything: A deep dive into Value Categories
#114Earlier quoted context omitted.
Systems programming in the large is hard, owning the category for decades harder still. Even languages that have tried to fast-follow and disrupt C++ end up looking a lot like C++. There is an irreducible complexity.
I have no problem with systems programming issues. That complexity is essential complexity inherent in the problem itself, regardless of language. I have a problem with C++’s accidental complexity. I find C much more tractable. It certainly has a few of its own footguns, but it has much less accidental complexity.
And here we see this principle rear its ugly head yet again. In this case, its the combination of exceptions, manual memory allocation and the desire to make things work efficiently - of which the move constructor was developed as a "solution"
Re: C++ std::move doesn't move anything: A deep dive into Value Categories
#115Earlier quoted context omitted.
While I share the sentiment, compare C#14 with C# 1.0, Java 25 with Java 1.0, Python 3.14 with Python 1.0. While C++ might be worse, when you have 300+ doing proposals every three years, others aren't safer from similar churn, even if on smaller volume, and trying to keep backwards compatibility going. And we all know what happened in Python. Also Rust editions contrary to what many think, only cover a specific set o…
> nor there is support for binary libraries. This is a weird call-out because it's both completely incorrect and completely irrelevant to the larger point. Rust absolutely supports binary libraries. The only way to use a rust library with the current rust compiler is to first compile it to a binary format and then link to it. More so than C++ where header files (and thus generics via templates) are textual. Cargo, th…
Re: C++ std::move doesn't move anything: A deep dive into Value Categories
#116> So the standard library plays it safe: if your move constructor might throw (because you didn’t mark it noexcept), containers just copy everything instead. That “optimization” you thought you were getting? It’s not happening. This is a bit of a footgun and clang-tidy has a check for it: performance-noexcept-move-constructor. However, I don't think it's enabled by default!
Re: C++ std::move doesn't move anything: A deep dive into Value Categories
#117Earlier quoted context omitted.
> nor there is support for binary libraries. This is a weird call-out because it's both completely incorrect and completely irrelevant to the larger point. Rust absolutely supports binary libraries. The only way to use a rust library with the current rust compiler is to first compile it to a binary format and then link to it. More so than C++ where header files (and thus generics via templates) are textual. Cargo, th…
Rust does, Rust editions do not have a story for them.
Re: C++ std::move doesn't move anything: A deep dive into Value Categories
#118Earlier quoted context omitted.
Well, no, because CAN take isn't the same as WILL take. Changing something to an rvalue means it'll now match a move constructor, but there is no guarantee a move constructor will be used, even if defined, because you've got classes like std::vector that are picky and are explicitly looking for a noexcept move constructor.
In that sense, std::move() is no different than other passing semantics. Just because you wrote at the call site that you want to pass a copy of your object doesn't mean that the callee will actually make a copy of it.
If we have foo(std::string a, std string b), and then call it like this:
std::string x;
std::string y;
foo(std::move(x), y);
Then x will be moved into a, and y will be copied into b.
The callee has no say in this - it's just the compiler implementing the semantics of the language.
Re: C++ std::move doesn't move anything: A deep dive into Value Categories
#119About 28 years ago, I figured out that I’m just not smart enough to use C++. There are so many foot guns and so much rampant complexity that I can’t keep it all straight. I crave simplicity and it always felt like C++ craved the opposite.
Re: C++ std::move doesn't move anything: A deep dive into Value Categories
#1201. Move semantics are to handle ownership. Ownership is a first-class concept in Rust. This is why;
2. C++ smart pointers (eg std::unique_ptr) are likewise to handle ownership and incur a runtime cost where in Rust they are handled by the compiler with no runtime cost. Yes you can "cheat" (eg std::unique_ptr::get) and people do (they have to) but this is a worse (IMHO) version than the much-maligned Rust unsafe blocks;
3. Not only do all features have a complexity cost but that curve is exponential because of the complexity of interactions, in this case move semantics and exceptions. At this point C++'s feature set combined with legacy code support is not just an albatross around its neck, it's an elephant seal; and
4. There's a 278 page book on C++ initialization [2].
My point here is that there are so many footguns here combined with the features of modern processors that writing correct code remains a Herculean (even Sisyphean) task.
But here's the worst part: IME all of this complexity tends to attract a certain kind of engineer who falls in love with their own cleverness who creates code using obscure features that nobody else can understand all the true implications (and likely they don't either).
Rust is complex because what you're doing is complex. Rust isn't a panacea. It solves a certain class of problems well and that class is really important (ie memory safety). We will be dealing with C++ buffer overflow CVEs until the heat death of the Universe. But one thing I appreciate about languages like Go is how simple they are.
I honestly think C++ is unsalvageable given its legacy.