Live data from Hacker News

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

0xghost.dev

81–90 of 220 posts

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

#81

[flagged]

Coming from other languages with generics, it took a while for me to internalize SFINAE when writing templated code.

Luckily, with C++17's if-constexpr and C++20's concepts, SFINAE has become mostly obsolete for new C++ code (unless you have/want to support older C++ standards).

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

#82
post #77
post #64

Earlier quoted context omitted.

There was no Rust in 2011.

The point is not a comparison with Rust per-se, but the fact that a better implementation of the idea was mathematically and/or technically possible; and the personal opinion that such huge footguns that the language accumulates over the years are maybe signals of having needed more thought to them before they were considered ready. e.g. if something as simple of a inconspicuous std::move in the wrong place can break…

It took 13 years to get C++11, actually.

Go's discussion is interesting, given how much programming language design history, and flaws of existing languages, they ignore to this day.

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

#83

Earlier quoted context omitted.

Exceptions should never be enabled by default. We live in a 64bit world so allocations failing indicates some other problem.

What does processor but width have to do with the likelihood of allocation failures?

640K ought to be enough for anybody!

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

#85

Earlier quoted context omitted.

Exceptions should never be enabled by default. We live in a 64bit world so allocations failing indicates some other problem.

What does processor but width have to do with the likelihood of allocation failures?

I think what he means is that on a 64-bit system you have a massive virtual address space (typically only 48-bit, but that's still 256TB), and since malloc allocates from virtual address space, not limited by physical memory, it is unlikely you will get a malloc failure (unless you are trying to allocate more than 256TB per process, maybe due to a memory leak).

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

#86

Earlier quoted context omitted.

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

Yeah no.

In Rust if you pass say a Box (not a reference, the actual object) into a function foo, it's gone, function foo might do something with that boxed goose or it might not, but it's gone anyway. If a Rust function foo wanted to give you it back they'd have to return the Box

But C++ doesn't work that way, after calling foo my_unique_ptr is guaranteed to still exist, although for an actual unique_ptr it'll now be "disengaged" if foo moved from it. It has to still exist because C++ 98 (when C++ didn't have move semantics) says my_unique_ptr always gets destroyed at the end of its scope, so newer C++ versions also destroy my_unique_ptr for consistency, and so it must still exist or that can't work.

Creating that "hollowed out" state during a "move" operation is one of the many small leaks that cost C++ performance compared to Rust.

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

#87
post #82
post #77

Earlier quoted context omitted.

The point is not a comparison with Rust per-se, but the fact that a better implementation of the idea was mathematically and/or technically possible; and the personal opinion that such huge footguns that the language accumulates over the years are maybe signals of having needed more thought to them before they were considered ready. e.g. if something as simple of a inconspicuous std::move in the wrong place can break…

It took 13 years to get C++11, actually. Go's discussion is interesting, given how much programming language design history, and flaws of existing languages, they ignore to this day.

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 the name of backwards compatibility, but at this pace, how will C++36 look like?

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

#88

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

I wouldn't say issues like this are dues to irreducible complexity, but more symptomatic of long-lived languages that continually get extended but don't give up on backwards compatibility. It's basically the 2nd law of thermodynamics applied to programming languages that they will eventually die due to increased entropy.

Maybe if move semantics, and noexcept, had been designed into C++ from the beginning then the designers might have chosen to insist that move constructors be noexcept, but since these were added later there is code out there with move constructors that do throw exceptions...

Note by the way that the issue being described isn't strictly about std::move or move semantics in general, but more about the STL and containers like std::vector that have chosen to define behavior that makes noexcept move constructors necessary to be used when reallocating.

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

#90
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(…

I would argue performance-noexcept-move-constructor should always be on. Move constructors should almost always be noexcept since they typically just move pointers around and don't do allocations normally.
Post reply on HN