[HN Gopher] C++ move semantics from scratch (2022)
       ___________________________________________________________________
        
       C++ move semantics from scratch (2022)
        
       Author : todsacerdoti
       Score  : 75 points
       Date   : 2025-11-03 14:16 UTC (5 days ago)
        
 (HTM) web link (cbarrete.com)
 (TXT) w3m dump (cbarrete.com)
        
       | revivalizer wrote:
       | This 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 wrote:
         | I 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 wrote:
           | I 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 wrote:
             | Apologies, 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.ht
             | m...
             | 
             | The confusion kind of speaks for itself. The language is a
             | construction set where the primary building block is razor
             | blades.
        
               | einpoklum wrote:
               | It'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.
        
               | quuxplusone wrote:
               | Ten 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,_P
               | lus...
               | 
               | 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 wrote:
         | I retired from wanting to write C++ when Scott Meyers retired
         | from writing more Effective Modern C++.
        
           | webdevver wrote:
           | scott could not have picked a better time to retire tbh. dude
           | really sold the top.
        
         | wvenable wrote:
         | I 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 wrote:
       | The 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 wrote:
         | If 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 wrote:
         | > 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 wrote:
         | Mathematics doesn't need to remain backward compatible.
        
           | somethingsome wrote:
           | IMO math is backward compatible by default unless you change
           | the foundational axioms (rare occurrence).
           | 
           | In particular you can most of the time define morphisms
           | between concepts.
        
       | criemen wrote:
       | Would 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 wrote:
         | Correct. 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 wrote:
           | Sorry 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/n13... move designs
           | 
           | * https://www.foonathan.net/2017/09/destructive-move/
        
         | kccqzy wrote:
         | Deep 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 wrote:
           | I'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 wrote:
           | No, it should move properly when passing by value (as in,
           | essentially the rust move semantics). If you want a copy,
           | that should be explicit.
        
             | hyghjiyhu wrote:
             | Moving by default would be too much of a footgun without a
             | borrow checker imo.
        
           | cjfd wrote:
           | It certainly makes things easier. But it also makes some
           | things very, very, very inefficient. I want a list with
           | millions/billions of elements. I want to regularly change one
           | of the elements somewhere in the middle. Good luck with the
           | copying.
        
             | Maxatar wrote:
             | Why would you copy a whole list to modify a single element?
        
           | vlovich123 wrote:
           | Then explain that const isn't deep and a const container can
           | end up mutating state? Pretending like c++ has a consistent
           | philosophy is amusing and pretending this happened because of
           | pedagogy is amusing. It happened because in c assignment is a
           | copy and c++ inherited this regardless of how dumb it is as a
           | default for containers.
        
             | kccqzy wrote:
             | In C++ regular types have the property that const is deep.
             | If you have a const std::vector<int> the you can't modify
             | any of the integers contained in this container. Naturally
             | for flexibility reasons not all types are regular, pointers
             | being the prominent exception, and things like
             | std::string_view being modern examples of non-regular
             | types.
        
               | vlovich123 wrote:
               | I feel like you could benefit from watching Scott Meyers
               | about the silliness in C++ if you feel like there's a
               | consistent and logical feel to the language. A lot of
               | this is c++-isms masquerading sensible ideas through
               | official terms (regular and non-regular types)
        
         | HarHarVeryFunny wrote:
         | C++ supports both pass-by-value and pass-by-reference
         | parameters. Pass-by-value means making a copy (a deep copy if
         | it's a deep type), but you could always choose to optimize by
         | passing large parameters by reference instead, and this is
         | common practice.
         | 
         | The real value of std::move is cases where you to HAVE to
         | (effectively) make a deep copy, but still want to avoid the
         | inefficiency. std::move supports this because moving means
         | "stealing" the value from one variable and giving it to
         | another. A common use case is move constructors for objects
         | where you need to initialize the object's member variables, and
         | can just move values passed by the caller rather than copying
         | them.
         | 
         | Another important use case for std::move is returning values
         | from functions, where the compiler will automatically use move
         | rather than copy if available, allowing you to define functions
         | returning large/complex return types without having to worry
         | about the efficiency.
        
           | tubs wrote:
           | (More so since c++17) std::move should not be used for
           | returns because this pessimises optimisations.
        
           | w10-1 wrote:
           | 1990's C practice was to document whether initialization
           | values were copied or adopted. I'm curious why the concept
           | became "move" rather than "adopt", since move gives the
           | parameter/data agency instead of giving agency to the
           | consuming component.
        
             | HarHarVeryFunny wrote:
             | I'm not sure how any notion of ownership and adoption in C
             | would carry over to C++, since one of the problems with C
             | is that it didn't define ownership. If you have a pointer
             | value in C it means nothing about ownership.
             | 
             | Given the limits of C, "adopting" a pointer variable would
             | just mean that the foster-parent now had a copy of the
             | pointer, and was considered owner of it, now responsible
             | for freeing it too presumably. It's basically a move,
             | except the source can now mess things up by still using the
             | adopted value after the adoption.
        
         | anonnon wrote:
         | > defaulted to deep copy semantics
         | 
         | It defaulted to pass-by-value, with _shallow_ copy semantics,
         | as opposed to pass by reference.
        
           | HarHarVeryFunny wrote:
           | No, pass-by-value means copying, which means whatever the
           | copy constructor of the type implements, which for all
           | standard types means a deep copy.
           | 
           | You COULD define you own type where the copy constructor did
           | something other than deep copy (i.e. something other than
           | copy!), just as you could choose to take a hand gun and shoot
           | yourself in the foot.
        
             | Maxatar wrote:
             | You seem to misunderstand the meaning of deep versus
             | shallow copy. This distinction has to do with how
             | references/pointers get copied.
             | 
             | In C++ the compiler generated copy constructors are
             | shallow, not deep, meaning that if you want a copy to
             | reconstruct the object being pointed to, you can not use
             | the default copy constructor but need to supply your own
             | explicit copy constructor to do so.
        
               | HarHarVeryFunny wrote:
               | No - you are confusing C and C++.
               | 
               | In C a structure passed by value will just be shallow-
               | copied.
               | 
               | In C++ a structure/class passed by value will by copied
               | using whatever copy constructor is defined by the
               | structure type. If there is no explicitly defined copy
               | constructor, then a default copy constructor will be used
               | that does member-wise copy using the member's copy
               | constructors.
               | 
               | So, unless you have chosen to shoot yourself in the foot
               | by defining a class who's copy constructor doesn't do a
               | deep copy, then C++ pass-by-value will indeed do a deep
               | copy.
               | 
               | The case of a structure with a pointer member (e.g. maybe
               | you defined your own string class) is certainly one where
               | you would need to define an appropriate copy constructor,
               | and not doing so would indeed be shooting yourself in the
               | foot.
        
               | Maxatar wrote:
               | >So, unless you have chosen to shoot yourself in the foot
               | by defining a class who's copy constructor doesn't do a
               | deep copy, then C++ pass-by-value will indeed do a deep
               | copy.
               | 
               | You either are misspeaking, deeply confused, or quite
               | possibly both.
        
               | HarHarVeryFunny wrote:
               | Do you agree that C++ pass-by-value is using copy
               | constructors?
               | 
               | Do you agree that the copy constrictors of the C++
               | standard library (STL) all do deep copy?
               | 
               | Do you agree that if you write your own class with a raw
               | pointer member, you would need to write a copy
               | constructor?
               | 
               | So, what exactly are you disagreeing about ?!
               | 
               | You seem to be saying that if you wrote a C-style
               | structure (no constructors) with a pointer member, then
               | C++ would behave like C, which is true, but irrelevant.
               | We're talking about C++ vs C, but since C++ is a superset
               | of C, then yes you can still screw yourself C-style if
               | you choose to.
        
             | jstimpfle wrote:
             | "Deep copy" is quite hand-wavy. A useful program is not a
             | collection of trees that you can just copy like that.
             | Instead, typical program's data structures tend to have
             | lots of references that let you go from anywhere to just
             | about anywhere else. That's why "deep copy" is just a rough
             | idea that may work for simple container types but not much
             | else.
        
       | mlmonkey wrote:
       | Whenever 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 wrote:
         | && 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 wrote:
         | If 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 wrote:
           | > 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 wrote:
             | Your 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?
        
           | djmips wrote:
           | Unless, you work with a large team of astronauts who ignore
           | the coding guidelines that say to stick with a core subset
           | but leadership doesn't reign them in and eventually you end
           | up with a grotesque tower of babel with untold horrors that
           | even experienced coders will be sickened by.
        
           | pizza234 wrote:
           | > 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.
           | 
           | I think there was a comment on HN by Walter Bright, saying
           | that at some point, C++ became too complex to be fully
           | understood by a single person.
           | 
           | > You can also mostly just stick to the core subset of the
           | language
           | 
           | This works well for tightly controlled codebases (e.g. Quake
           | by Carmack), but I'm not sure how this work in general,
           | especially when project owners change over time.
        
         | einpoklum wrote:
         | > _" Whenever I'm dealing with C++" ... "I have steadfastly
         | avoided dealing with C++"_
         | 
         | So, basically, you're just trolling us about a language you
         | avoid using. Thanks, that's very helpful.
        
         | thw_9a83c wrote:
         | > Whenever I'm dealing with C++, I get tripped by...
         | 
         | Problem: Whenever I'm dealing with X, I get tripped by Y.
         | 
         | Solution A: Don't deal with X.
         | 
         | Solution B: Understand Y, when dealing with X.
         | 
         | For && meaning, this article [1] is still very useful.
         | 
         | [1]: https://isocpp.org/blog/2012/11/universal-references-
         | in-c11-...
        
       | web3-is-a-scam wrote:
       | I 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 wrote:
         | C++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 wrote:
         | for me, its C++11. the absolute pinnacle of mankind.
         | 
         |  _everything_ has been going downhill since then. coincidence?
         | i think not!
        
           | medler wrote:
           | The 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 wrote:
             | Yes! 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 wrote:
               | Same, 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.
        
               | spacechild1 wrote:
               | > 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`.
               | 
               | Yes, but here we're getting deep into platform specifics.
               | An even bigger pain point are thread priorities. Windows,
               | macOS and Linux differ so fundamentally in this regard
               | that it's really hard to create a meaningful abstraction.
               | Certain things are better left to platform APIs.
        
               | nuertey2025 wrote:
               | ```c++
               | 
               | // To lessen verbosity, try defining the following
               | convenience aliases in a header:
               | 
               | using SystemClock_t = std::chrono::system_clock;
               | 
               | using SteadyClock_t = std::chrono::steady_clock;
               | 
               | using HighClock_t = std::chrono::high_resolution_clock;
               | 
               | using SharedDelay_t =
               | std::atomic<SystemClock_t::duration>;
               | 
               | using Minutes_t = std::chrono::minutes;
               | 
               | using Seconds_t = std::chrono::seconds;
               | 
               | using MilliSecs_t = std::chrono::milliseconds;
               | 
               | using MicroSecs_t = std::chrono::microseconds;
               | 
               | using NanoSecs_t = std::chrono::nanoseconds;
               | 
               | using DoubleSecs_t = std::chrono::duration<double>;
               | 
               | using FloatingMilliSecs_t = std::chrono::duration<double,
               | std::milli>;
               | 
               | using FloatingMicroSecs_t = std::chrono::duration<double,
               | std::micro>;
               | 
               | ```
        
         | spacechild1 wrote:
         | Have you even tried modern C++? If no, how can you say that
         | C++98 was peak?
         | 
         | As someone who grew up with modern C++, I can't even imagine
         | going back to C++98 because it feels so incredibly verbose.
         | Just compare how you iterate over a std::map and print its
         | items in C++98 vs C++23:                 // C++98:       for
         | (std::map<std::string, int>::const_iterator it = m.begin(); it
         | != m.end(); ++it) {           std::cout << it->first << ": " <<
         | it->second << "\n";       }            // C++23:       for
         | (const auto& [key, value] : m) {           std::print("{}:
         | {}\n", key, value);       }
         | 
         | Then there are all the features I would miss, for example:
         | - auto       - lambda functions and std::function       - move
         | semantics       - std::unique_ptr and, to a lesser extent,
         | std::shared_ptr       - variadic templates       -
         | std::filesystem       - std::chrono       - std::thread,
         | std::mutex, std::atomic, etc.       - a well-defined memory
         | model for multi-threaded programs       - unordered containers
         | - structured bindings       - class template argument
         | deducation       - std::format       - std::optional       -
         | std::variant       - etc.
        
           | jstimpfle wrote:
           | It's getting ever more complicated and involved. I need both
           | of my hands to count the number of times I've tried coming
           | back to C++ and use its object model for good effect. C++ is
           | fine for simple things, and if you're smart you can scale it
           | a long way (since it contains C).
           | 
           | But when you try to use all these funny features you're
           | enumerating there for something serious, it will invariably
           | end up in an overcomplicated slow compiling morass. Even just
           | trying to make the types click for inserting something into a
           | non-trivial templatized hashmap becomes a tedious act, and
           | the IDE cannot help anymore either.
           | 
           | (Last issue I had was with catching some exception just to
           | ignore it. Turned out _catch(std::bad_alloc)_ doesn 't work,
           | you need write _catch (std::bad_alloc &)_.)
           | 
           | I prefer writing simple C-style C++ where I write whole
           | subsystems from scratch, and I can be very clear about the
           | semantics from the start, design in what matters, and leave
           | out what doesn't. Adding all the built-in object semantics
           | baggage is too much overhead.
        
             | spacechild1 wrote:
             | It's not like I use these things just for the sake of it.
             | All of the things I've listed above solve real practical
             | issues or make the code more readable. I don't really see
             | how they would influence the overall program architecture,
             | let alone in a negative way.
        
           | paulddraper wrote:
           | Moreover, most of the footguns were present in C++98.
           | 
           | Modern C++ is easier and safer than it has ever been.
           | 
           | The biggest slight is simply that there are high quality
           | alternatives.
        
           | nurettin wrote:
           | As someone who grew up with turbo c++ I would also miss
           | pretty much all of these (maybe not variadic template args)
           | but at least boost covers the library parts.
        
         | almostgotcaught wrote:
         | hn has become literally just twitter level hottakes
        
       | macleginn wrote:
       | Irregardless of the main topic of the post, combining a struct
       | definition with a constructor is additionally confusing.
        
       | anonnon wrote:
       | > int& lvalueRef = (int&)x;
       | 
       | > int&& rvalueRef = (int&&)x;
       | 
       | Why are they casting x here?
        
       | DLoupe wrote:
       | "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 wrote:
         | clang-tidy has a check for this.
         | 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.
        
       ___________________________________________________________________
       (page generated 2025-11-08 23:02 UTC)