Live data from Hacker News

Move in C++ without a std:move

andreasfertig.com

51–60 of 75 posts

Re: Move in C++ without a std:move

#51

- stupid question, since we are on the topic of c++, i finished reading through learncpp.com - how do I take this from 0 to the guy that builds a play station 3 emulator? - like seriously what kind of step by step projects or learning experiences in increasing order of difficulty do you recommend to get really really good at c++

The fun thing about C++ is that it’s really hard. The even more fun thing is that the domain knowledge behind is even harder - game engines, high performance clusters, emulators, real time simulations, rendering engines, high frequency trading - so more often than not most C++ devs commit to learning a language subset and then focus their energy on the task at hand. A PS3 emulator might be a switch statement (not rea…

> The fun thing about C++ is that it’s really hard.

C++ definitely has a higher cognitive load than your average interpreted language. However, a big part of that cognitive load is due to support for highly optimized scenarios such as return value optimization. Most people write code that doesn't require it at all, and that's perfectly fine. The same goes for move semantics. You can spend a whole career writing code where all your classes do deep copies when passing objects by value. The compiler even graciously helps you not have to write all constructors and assignment operators to have your POCO class work out of the box. But once you feel the need to avoid those copies then you need to know what to do to nudge the compiler do that for you. That is a while subtle dance. That's when the cognitive load starts growing.

Re: Move in C++ without a std:move

#52

- stupid question, since we are on the topic of c++, i finished reading through learncpp.com - how do I take this from 0 to the guy that builds a play station 3 emulator? - like seriously what kind of step by step projects or learning experiences in increasing order of difficulty do you recommend to get really really good at c++

> like seriously what kind of step by step projects or learning experiences in increasing order of difficulty do you recommend to get really really good at c++

I'm not sure if you're personally interested in this, but the main way I learned is by writing my own game engine (Casey Muratori's Handmade Hero-style) and writing mods for games (even by reverse engineering). It actually teaches you almost everything you need to know both from a language perspective AND it forces you to understand each individual step of how a program works (input/audio/networking/graphics/logic). You can go step-by-step mastering each thing as you go.

Re: Move in C++ without a std:move

#53

Earlier quoted context omitted.

The fun thing about C++ is that it’s really hard. The even more fun thing is that the domain knowledge behind is even harder - game engines, high performance clusters, emulators, real time simulations, rendering engines, high frequency trading - so more often than not most C++ devs commit to learning a language subset and then focus their energy on the task at hand. A PS3 emulator might be a switch statement (not rea…

> The fun thing about C++ is that it’s really hard. C++ definitely has a higher cognitive load than your average interpreted language. However, a big part of that cognitive load is due to support for highly optimized scenarios such as return value optimization. Most people write code that doesn't require it at all, and that's perfectly fine. The same goes for move semantics. You can spend a whole career writing code…

The hardest part of C++ are it's lifetime rules, which are in fact extremely difficult to grasp. There's essentially a unique(ish) ruleset for each class of object and misinterpreting one of them (no matter how obscure) can easily cause UB.

see https://en.cppreference.com/cpp/language/lifetime

Re: Move in C++ without a std:move

#54

Earlier quoted context omitted.

N/RVO works by (at the machine language level, of course) rewriting the function signature to return void and take an extra pointer parameter, which is written to before returning. If you're returning a newly-constructed object, the compiler can rewrite that into calling the constructor on the pointer, but if you're returning a named object, the class may have a non-trivial destructor that needs to run after the move…

I'm sorry, this comment is completely wrong. NRVO does not affect the ABI of the function. It cannot affect the ABI, for whether or not it kicks in depends on the body of the function, and affecting the ABI would make it impossible to use it if only the declaration appears in a header. The correct explanation is this: In C++, classes with nontrivial destructors or copy/move constructors are considered nontrivial for…

> Despite its name, NRVO is not actually an 'optimization' in the compiler. The optimizer plays no role in it, since the optimizer is fulfilling the requirements of the abstract machine. Instead, it is a set of conditions that allows the frontend to omit calls to copy constructors, etc. under specific circumstances.

That's semantics. The way the compiler is structured and in which component the transformation is implemented has no bearing on whether something is an optimization.

Re: Move in C++ without a std:move

#56

Earlier quoted context omitted.

They probably _were_, since lower level code representations often has little notion of complex types and their semantics they could be kept clean and focused on machine code, however type inference in a language like C++ complicates such matters immensly since an assignment can be both a register move and a function call. Template resolution solved that in the past, but C++ today allows auto in so many places that I…

> Template resolution solved that in the past, but C++ today allows auto in so many places that I'm uncertain that it can be done without some flow based support (if constexpr comes to mind). This concern is unfounded. The auto keyword in C++ acts as mere syntactic sugar. It works only when the compiler is able to tell exactly what's the type by evaluating the expression. The auto keyword is also considered a code sm…

> The auto keyword is also considered a code smell for the same reason: just because the compiler can tell exactly what the type is expected to be, that does not mean the developer can. Therefore it makes the code harder to reason about.

This really depends though. In many cases even the programmer can tell the type of auto because its on the very same line and not using auto would mean needlessly repeating it.

In other cases (e.g. iterators) the programmer also doesn't need to care about the concrete type.

Re: Move in C++ without a std:move

#57

Earlier quoted context omitted.

I'm sorry, this comment is completely wrong. NRVO does not affect the ABI of the function. It cannot affect the ABI, for whether or not it kicks in depends on the body of the function, and affecting the ABI would make it impossible to use it if only the declaration appears in a header. The correct explanation is this: In C++, classes with nontrivial destructors or copy/move constructors are considered nontrivial for…

> Despite its name, NRVO is not actually an 'optimization' in the compiler. The optimizer plays no role in it, since the optimizer is fulfilling the requirements of the abstract machine. Instead, it is a set of conditions that allows the frontend to omit calls to copy constructors, etc. under specific circumstances. That's semantics. The way the compiler is structured and in which component the transformation is impl…

[flagged]

Re: Move in C++ without a std:move

#58
post #8

Earlier quoted context omitted.

This is one case where Rust benefited from C++’s experience — move by default with opt-in clone/copy is IMO the better setup.

And the most important idea: destructive moves. Since C++ doesn't track lifetimes it has to leave the object in a "valid state" after a move and the destructor still runs which has to have a check if it should do something or not.

But the compiler won't necessarily generate any code for the destructor:

https://godbolt.org/z/PMando5x4

Re: Move in C++ without a std:move

#59
post #8

Earlier quoted context omitted.

This is one case where Rust benefited from C++’s experience — move by default with opt-in clone/copy is IMO the better setup.

This is an easy mistake to make but it's not what happened Programmers already knew (~20 years ago) when the C++ move feature was designed that what people want is the destructive move assignment semantic, the thing Rust has today. Other languages did have that. But C++ 98 already existed and WG21 already did not want to make it difficult to take your crusty 10+ year old C++ codebase, slap a sticker on it and say thi…

> For example std::unique_ptr looks like it's Box but it's not, it's actually Option>, even newer types often do this but they might be more embarrassed about it.

This would be the case even with destructive moves unless you also add some way for std::optional> to be no larger than a pointer by letting std::optional take advantage of the fact that a non-null std::unique_ptr has a bit representation that leaves room for sentinel values.

Also, at the language level, C++ moves are sort-destructive as the moved from object only has to guarantee to be able to run the destructor. E.g. you could still have a std::nonull_ptr where move sets the internal pointer to zero but calling anything except the destructor on such an instance throws / calls std::terminate() / is UB. It's only the stdlib types that make additional guarantees - because in most cases it can be done without additional cost.

Re: Move in C++ without a std:move

#60
post #27
post #24

Earlier quoted context omitted.

BTW, Rust's lifetime annotations for borrowed references are a mostly orthogonal feature. Liveness of objects for move/drop semantics is tracked differently, without any syntax and with implicit runtime drop flags where necessary. C++ could probably add the same deinitialized/moved-from state tracking (with an opt-in for back compat sake) purely to avoid dtor bloat, without having to add safety of borrow checking.

> C++ could probably add the same deinitialized/moved-from state (with an opt-in for back compat sake) purely to avoid dtor bloat, without having to add safety of borrow checking. There is a lot of talk in the C++ committee about this. The details are complex in some obscure cases.

At the very leas you'd also need to fix the caller-destructed ABI mess to get a 100% solution.
Post reply on HN