Live data from Hacker News

C++ std::move doesn't move anything: A deep dive into Value Categories

0xghost.dev

31–40 of 220 posts

Re: C++ std::move doesn't move anything: A deep dive into Value Categories

#31

I don’t think this is particularly insightful, as move semantics and r-values are higher level language semantics, nothing more and nothing less. Rust’s borrow checker doesn’t actually borrow anything either, it’s operating on a similar level of abstraction.

> Rust’s borrow checker doesn’t actually borrow anything either Why would it? It's called the borrow checker , not the borrower. So it checks that your borrows are valid. std::move looks and feels like a function, but it doesn't do what it says , it makes objects movable but does never moves them (that's up to whatever is using the value afterwards). If you want something similar in Rust, Pin is a much better candida…

Sure, but from the perspective of the code that has the move() its good to assume the value is moved at that call, which I guess was the intention of picking the name.

Re: C++ std::move doesn't move anything: A deep dive into Value Categories

#34

Earlier quoted context omitted.

Can you show an example of what you mean? My claim is that, if I call `foo(std::move(myObj))`, it is statically knowable if `foo` receives a copy of `myObj` or whether it is moved to it. Of course, `foo` can choose to further copy or move the data it receives, but it can't choose later on if it's copied or not. Now, if I give `foo` a pointer to myObj, it could of course choose to copy or move from it later and based…

> Can you show an example of what you mean? void foo(std::unique_ptr && p) { std::random_device rdev {}; auto dist = std::uniform_int_distribution (0, 1); if (dist(rdev)) { auto pp = std::move(p); } }

This is exactly what I meant as irrelevant.

If I call `foo(std::move(my_unique_ptr))`, I know for sure, statically, that my_unique_ptr was moved from, as part of the function call process, and I can no longer access it. Whether `foo` chooses to further move from it is irrelevant.

Re: C++ std::move doesn't move anything: A deep dive into Value Categories

#35
post #22

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

Most sensible Compiler flags aren't enabled by default... I keep a list of arguments for gcc to make things better, but even then you'll also wanna use a static analysis tool like clang-tidy

Re: C++ std::move doesn't move anything: A deep dive into Value Categories

#37
Regarding mistake 1: return std::move(local_var), it is worth clarifying why this is technically a pessimization beyond just breaking NRVO. It comes down to the change in C++17 regarding prvalues.

> Pre-C++17, a prvalue was a temporary object.

> Post-C++17, a prvalue is an initializer. It has no identity and occupies no storage until it is materialized.

Re: C++ std::move doesn't move anything: A deep dive into Value Categories

#38
post #22

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

The reason performance-noexcept-move-constructor is not enabled by default is likely because blindly applying noexcept is dangerous if the underlying logic isn't actually exception-free. If you let clang-tidy slap noexcept on a move constructor that does end up throwing (perhaps because it calls into a legacy member or allocates memory internally), the runtime behavior changes from caught exception to std::terminate().

Re: C++ std::move doesn't move anything: A deep dive into Value Categories

#39
> This code works. It compiles. It runs. But depending on how you’ve implemented your types, it might be performing thousands of expensive copy operations instead of cheap moves without you realizing it.

I've spent the last two decades in the .net platform. But for a decade or so before that I was a C++/Unix dev. I remember old style "C with classes" C++ as being fairly small and elegant, and approximately as easy to reason about as C# - albeit that you had the overhead of tracking object ownership and deallocation.

What the language has become now, boggles my mind. I get hints of elegance/power and innovation when I read about it, but the sheer number of footguns is astonishing. I'm very sure that I'm not clever enough to understand it.

But some very smart people have guided the language's evolution. So, what are the forces that have determined the current state of C++?

Re: C++ std::move doesn't move anything: A deep dive into Value Categories

#40

> This code works. It compiles. It runs. But depending on how you’ve implemented your types, it might be performing thousands of expensive copy operations instead of cheap moves without you realizing it. I've spent the last two decades in the .net platform. But for a decade or so before that I was a C++/Unix dev. I remember old style "C with classes" C++ as being fairly small and elegant, and approximately as easy to…

> So, what are the forces that have determined the current state of C++?

A subset of the language aimed at library writers. As a user of those libraries all these weirdo features are likely to be transparent.

Post reply on HN