This post is part of my series comparing C++ to Rust, which I introduced with a discussion of C++ and Rust syntax. In this post, I discuss move semantics. This post is framed around the way moves are implemented in C++, and the fundamental problem with that implementation, With that context, I shall then explain how Rust implements the same feature. I know that move semantics in Rust are often confusing to new Rustaceans – though not as confusing as move semantics in C++ – and I think an exploration of how move semantics work in C++ can be helpful in understanding why Rust is designed the way it is, and why Rust is a better alternative to C++.

  • HaraldvonBlauzahn@feddit.orgOP
    link
    fedilink
    arrow-up
    1
    ·
    edit-2
    4 days ago

    To sum up the main problem: Modern C++ does not implement destructive moves that are checked at compile time. Instead, moving from an object needs to take into account that it can potentially be used again, because in C++ it does not become destroyed or inaccessible as result of the move.

    This requires to set some objects - especially ones that track resources in an exclusive way - to an invalid or uninitialized state. For example, collections can be set to an empty collection, which is a valid state that frees resources. But a thread class would have an invalid thread id, and a unique smart pointer class a null pointer or a “deleted” flag, both of which need to be checked at run time.

    And this would be less of a problem if it were not a core promise if C++ that, by virtue of its constructors, any object that has successfully been constructed, is in a valid state (or never came into existence). (And the latter requires, of course, using exceptions and RAII, which in turn requires most code to be exception-safe, which, considering the many possibilities for UB to occur, is less trivial than it might sound…).