7 ms·
C++ move semantics from scratch (2022)
- revivalizer 1y agoThis is a really well written article that explains the concepts straightforwardly. I had never bothered to understand this before. ... because I gave up on C++ in 2011, after reading Scott Meyers excellent Effective C++. It made me realize I had no desire to use a language that made it so difficult to use it correctly.
- chuckadams 1y agoI had exactly the same reaction to Effective C++, and I'd learned it back in the 90's (my first compiler didn't even support templates!). It's a wonderful book for sure, but it's a wonderfully detailed map to a minefield. The existence of guidelines like the "Rule of 7" should be raising questions as to why such a rule needs to exist in the first place. As for this article, it really did de-mystify those strange foo&& things for me. I had no idea that they're functionally identical to references and that what C++ does with them is left up to convention. But I still felt like I had to fight against sanity loss from a horrid realization.
- scotty79 1y agoI don't get what's bad about rule 7. And I haven't really programmed in C++ for a decade. When you are calling derived object through a base class pointer you have a choice if you want to call the function of the base class or the function of the derived class. If you don't make it virtual it's called by pointer type, if you do, it's called by pointee type. Same goes for the destructors with only difference being that in case of virtual destructor the deatructor of a base class will be called automatically after the destructor of the derived class. So basically if you want to override methods or the destructor make your functions virtual, including the destructor. Does it lead to problems? Surely. Should all metods be virtual by default? Probably. Should there be some keyword that indicates in derived class that a method intentionally shadows a non virtual method from the base class? Yes. It's not a great human oriented design but it's consistent.
- chuckadams 1y agoApologies, I was referring to a "Rule of 7", but I more or less hallucinated it, since I'd heard the old "rule of 3" then "rule of 5" had been revised again, and thought they were maybe going with prime numbers? https://en.cppreference.com/w/cpp/language/rule_of_three.html https://en.cppreference.com/w/cpp/language/rule_of_three.htm... The confusion kind of speaks for itself. The language is a construction set where the primary building block is razor blades.
- einpoklum 1y agoIt's important to notice that you can keep well out of trouble by sticking to the rule of _zero_, i.e. relying on the defaults for copy&move ctors, assignment operators and destructor. So, the best advice is: Don't mess with the razor blades. And these days, C++ gives you enough in the standard library to avoid messing with them yourself. But since this is C++, you _can_ always open up the safety casing and messing with things, if you really want to.
- chuckadams 1y agoI'll admit, the Rule of Zero is the kind of thing I've been wanting all along, but so much code out there seems obsessed with micro-managing its pointer and reference semantics, and one still learns of their mistakes through segmentation faults and linker errors, at least in those codebases. Also, an artist friend tells me you can make some pretty keen sculpture with razor blades and a spot welder. Still recommended to use pliers and gloves tho.
- quuxplusone 1y agoTen years ago I gave a C++ conference talk titled "The Rule of Seven (Plus or Minus Two)" — a reference to the "magic number seven" meme https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus... and alluding to the fact that besides the well-established "Rule of 5" (copy construction and assignment, move construction and assignment, and destruction) a C++ class author also needs to at least think about whether to provide: default constructor, ADL swap, equality comparison operator, and/or specialized std::hash. And maybe a few more I'm forgetting right now. In hindsight (without rewatching it right now) I remember my thesis in that talk as erring too much on the side of "isn't this confusing? how exciting! be worried about the state of things!" These days I'd try harder to convey "it's not really that hard; yes there are a lot of customization knobs, but boring rules of thumb generally suffice; newbies shouldn't actually lose sleep over this stuff; just remember these simple guidelines."
- ckcheng 1y agoI retired from wanting to write C++ when Scott Meyers retired from writing more Effective Modern C++.
- webdevver 1y agoscott could not have picked a better time to retire tbh. dude really sold the top.
- wvenable 1y agoI like working in C++ (I don't do it professionally though) and I just never bother to read up on all the weird semantic stuff. I think the more you look into C++ the more irrational it seems but I generally just program in it like it's any other language and it's fine. It's actually even somewhat enjoyable.
- TimorousBestie 1y agoThe article is a really good exposition of move semantics, but unfortunately many modern C++ features benefit from the pedagogical technique of “imagine this feature didn’t exist, this is why someone would want to develop it.” I say unfortunately because this doesn’t scale. A junior programmer doesn’t have the time to process 30 years of C++’s historical development. Mathematics (which has a much longer history and the same pedagogical problem) gets around this by consolidating foundations (Bourbaki-style enriched set theory -> category theory -> homotopy type theory, perhaps?) and by compartmentalization (a commutative algebraist usually doesn’t care about PDEs and vice versa). I don’t see C++ taking either route, realistically.
- cyanmagenta 1y agoIf we want to make the math analogy, C++ seems more like the language of math (basic algebra, the notion of proofs, etc.) that everyone uses, and the compartmentalization comes when you start to apply it to specific fields (number theory, etc.). That same concept exists in the C++ community: the people who care about stuff like asynchronous networking libraries aren’t usually the people who care about SIMD math libraries, and vice versa. I also wonder if most junior C++ programmers can shortcut a bit by just using common patterns. Articles like these I’ve always thought were geared more toward experienced programmers who are intellectually curious about the inner workings of the language.
- einpoklum 1y ago> I don’t see C++ taking either route, realistically. But it has been taking the "compartmentalization" route: Once a new, nicer/safer/terser idiom to express something in code emerges, people being taught the language are directed to use that, without looking into the "compartment". Some of this compartmentalization is in the language itself, some in the standard library, and some is more in the 'wild' and programming customs. It's true, though, that if you want to write your own library, flexibly enough for public use - or otherwise cater to whatever any other programmer might throw at you - you do have to dive in rather deep into the arcane specifics.
- pesfandiar 1y agoMathematics doesn't need to remain backward compatible.
- criemen 1y agoWould it be fair to say that things are so complicated (compared to all other programming languages I've used in my professional life), because C++ pre-move semantics defaulted to deep copy semantics? It seems to be set apart in that choice from many other languages.
- htfy96 1y agoCorrect. As someone who maintain a 16-year-old C++ code base with new features added every day, The status quo is the best incremental improvement over deep copy semantics. There are better choices if everything is built from scratch, but changing wheels from a running car isn't easy.
- einpoklum 1y agoSorry to be the nitpicker here, but - the best incremental improvement would probably have seen move-destruction instead of just moves, which keep the source object alive and force the allowance for a valid 'empty' or 'dummy' state. See also: * https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1377.htm#Alternative https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n13... move designs * https://www.foonathan.net/2017/09/destructive-move/ https://www.foonathan.net/2017/09/destructive-move/
- kccqzy 1y agoDeep copy is pedagogically and semantically the right choice for any mutable containers. You either make containers immutable or copies deep. Otherwise it's just an invitation for subtle bugs.
- criemen 1y agoI'm not sure about that - every time I copy an object I have to think through what happens, no matter the default semantics. C++ makes the deep copy case easier than other programming languages without top-level built-in support.
- hgomersall 1y ago
- mlmonkey 1y agoWhenever I'm dealing with C++, I get tripped by the most basic of things: like for example, why use "&&" for what appears to be a pointer to a pointer? And if this indeed the case, why is int&& x compatible with int& y ?? Make up your mind: is it a pointer to a pointer, or a pointer to an int?!? I have steadfastly avoided dealing with C++ for almost 30 years, and I am grateful that I did not have to. It seems like such a messy language with overloaded operators and symbols ( don't even get me started on Lambdas!)
- wocram 1y ago&& is not a pointer to a pointer, it's a temporary value. There is a huge amount of cognitive overhead in normal cpp usage because over time we have found that many of the default behaviors are wrong.
- TinkersW 1y agoIf you had read like even the basic part of that article you would know that && is not a pointer to a pointer. Anyway C++ isn't as complicated as people say, most of the so called complexity exists for a reason, so if you understand the reasoning it tends to make logical sense. You can also mostly just stick to the core subset of the language, and only use the more obscure stuff when it is actually needed(which isn't that often, but I'm glad it exists when I need it). And move semantics is not hard to understand IMO.
- mlmonkey 1y ago> If you had read like even the basic part of that article you would know that && is not a pointer to a pointer. OK, let me ask this: what is "&&" ? Is it a boolean AND ? Where in that article is it explained what "&&" is, other than just handwaving, saying "it's an rvalue". For someone who's used to seeing "&" as an "address of" operator (or, a pointer), why wouldn't "&&" mean "address of pointer" ?
- throwaway150 1y agoYour comments are very confusing. > For someone who's used to seeing "&" as an "address of" operator (or, a pointer) You must be talking about "&something" which takes the "address of something" but the OP does not talk about this at all. You know this because you wrote in your other comment ... > And if this indeed the case, why is int&& x compatible with int& y ? So you clearly understand the OP is discussing "int&&" and "int&". Those are totally different from "&something". Even a cursory reading of the OP should tell you these are references, not the "address of something" that you're probably more familiar with. One is rvalue reference and the other is lvalue reference and I agree that the article could have explained it better what they mean. But the OP doesn't seem to be an introductory piece. It's clearly aimed at intermediate to advanced C++ developers. What I find confusing is that you're mixing up something specific like "int&&" with "&something", which are entirely different concepts. I mean when have you ever seen "int&" to be "address of" or "pointer"? You have only seen "&something" and "int*" and "int**" be "address of" or "pointer", haven't you?
- web3-is-a-scam 1y agoI loved writing C++ back in the day, C++98 was peak. I couldn’t fathom starting a new project with whatever the current C++ is now.
- vardump 1y agoC++98 forced the compiler to generate a lot of useless code. Newer semantics helps to remove this overhead. You can still write things the old way, if you like.
- webdevver 1y agofor me, its C++11. the absolute pinnacle of mankind. everything has been going downhill since then. coincidence? i think not!
- medler 1y agoThe new changes in C++14, 17, and 20 are really nice. It feels like the language keeps getting cleaner and easier to use well
- spacechild1 1y agoYes! Just to list a few personal highlights: C++14: - generalized lambda capture - generic lambdas C++17: - structured bindings - init statement for if - class template argument deduction (CTAD) - std::string_view - std::filesystem - std::variant - std::optional - std::to_chars() and std::from_chars() C++20: - std::format - coroutines (makes ASIO code so much cleaner!) - concepts - std::span - bit manipulation (<bit>) - std::bind_front - std::numbers (math constants)
- mrlongroots 1y agoSame, I don't understand the complaints against modern C++. A lambda, used for things like comparators etc, is much simpler than structs with operators overloaded defined elsewhere. My only complaint is the verbosity, things like `std::chrono::nanonseconds` break even simple statements into multiple lines, and you're tempted to just use uint64_t instead. And `std::thread` is fine but if you want to name your thread you still need to get the underlying handle and call `pthread_setname_np`. It's hard work pulling off everything C++ tries to pull off.
- macleginn 1y agoIrregardless of the main topic of the post, combining a struct definition with a constructor is additionally confusing.
- _zagj 1y ago> int& lvalueRef = (int&)x; > int&& rvalueRef = (int&&)x; Why are they casting x here?
- DLoupe 1y ago"Another difference in Rust is that values cannot be used after a move, while they simply "should not be used, mostly" in C++" That's one of my biggest issues with C++ today. Objects that can be moved must support a "my value was moved out" state. So every access to the object usually starts with "if (have-a-value())". It also means that the destructor is called for an object that won't be used anymore.
- krona 1y agoclang-tidy has a check for this. https://clang.llvm.org/extra/clang-tidy/checks/bugprone/use-after-move.html https://clang.llvm.org/extra/clang-tidy/checks/bugprone/use-... MSVC and the Clang static analyzer have a analysis checks for this too. Not sure about GCC. It's worth remembering though that values can be reinitialized in C++, after move.
- DLoupe 1y agoI think you missed my point. The problem is not lack of guarding against programmer mistakes. It's that the compiler generates unnecessary code.
- dh2022 1y agoArticles like these make me so glad I use C# and Python and don’t have to use C++.
- hkkwritesgmail 1y agoAt this point, I think we need a single C++ book that captures all the best improvements since C++98 and simply skips all legacy. Just skip it as if it does not exist. Only then will new programmers feel encouraged to look at C++ in a fresh new light. And the book remains thin.