Courses/C++/Move Semantics Advanced

    Lesson 20 • Advanced

    Move Semantics, Perfect Forwarding & Rvalue References

    Deep dive into rvalue references, std::forward, perfect forwarding, and copy elision — the mechanics that make modern C++ fast.

    What You'll Learn

    • Lvalue vs rvalue references (& vs &&)
    • Perfect forwarding with std::forward
    • Forwarding references vs rvalue references
    • RVO, NRVO, and guaranteed copy elision

    Lvalue vs Rvalue — Value Categories

    Every expression in C++ has a value category. An lvalue has an identity — you can take its address. An rvalue is a temporary that's about to be destroyed. Rvalue references (&&) let you "catch" temporaries and steal their resources instead of copying.

    CategoryExamplesCan take address?
    lvaluex, arr[0], *ptr, obj.memberYes (&x)
    rvalue42, x+y, "hello", func()No
    xvaluemove(x), static_cast<T&>(x)Expiring lvalue

    Rvalue References

    Understand lvalue vs rvalue references and overload resolution

    Try it Yourself »
    C++
    #include <iostream>
    #include <string>
    using namespace std;
    
    // lvalue reference: binds to named objects
    void processLvalue(string& s) {
        cout << "lvalue ref: " << s << endl;
    }
    
    // rvalue reference: binds to temporaries
    void processRvalue(string&& s) {
        cout << "rvalue ref: " << s << endl;
        // s itself is an lvalue inside this function!
        // Even though it was bound to an rvalue
    }
    
    // Overload resolution picks the right version
    void process(const string& s) {
        cout << "const lvalue 
    ...

    Perfect Forwarding with std::forward

    Perfect forwarding passes arguments to another function preserving their original value category. If the caller passed an rvalue, the inner function receives an rvalue. If an lvalue, it stays an lvalue. This is essential for factory functions, emplace methods, and generic wrappers.

    The trick: use a forwarding reference (T&& where T is deduced) combined with std::forward<T>(arg).

    Perfect Forwarding

    Forward arguments preserving their lvalue/rvalue category

    Try it Yourself »
    C++
    #include <iostream>
    #include <string>
    #include <memory>
    #include <utility>
    using namespace std;
    
    class Widget {
        string name;
        int value;
    public:
        Widget(const string& n, int v) : name(n), value(v) {
            cout << "Widget(copy '" << name << "')" << endl;
        }
        Widget(string&& n, int v) : name(move(n)), value(v) {
            cout << "Widget(move '" << name << "')" << endl;
        }
        void show() const { cout << name << " = " << value << endl; }
    };
    
    // Perfect forwarding: preserves valu
    ...

    Copy Elision & RVO

    See how the compiler eliminates unnecessary copies and moves

    Try it Yourself »
    C++
    #include <iostream>
    #include <vector>
    using namespace std;
    
    class Heavy {
        vector<int> data;
        string label;
    public:
        Heavy(string l, int n) : label(l), data(n, 42) {
            cout << "[" << label << "] Constructed (" << n << " ints)" << endl;
        }
        Heavy(const Heavy& o) : data(o.data), label(o.label + "_copy") {
            cout << "[" << label << "] COPIED" << endl;
        }
        Heavy(Heavy&& o) noexcept : data(move(o.data)), label(move(o.label) + "_moved") {
            cout << "[" << label <
    ...

    Common Mistakes

    ⚠️ Forwarding ref vs rvalue ref: T&& is a forwarding ref only when T is deduced. string&& is always an rvalue ref.

    ⚠️ Using std::move in return: Don't return move(local); — it prevents copy elision. Just return local;.

    ⚠️ Forwarding more than once: forward may move the argument. Forwarding the same argument twice can use a moved-from object.

    Pro Tips

    💡 Rule of thumb: Use std::move on rvalue references, std::forward on forwarding references. Never mix them.

    💡 Rely on copy elision: In C++17, returning a prvalue is guaranteed to elide. Write clean code and let the compiler optimise.

    💡 noexcept matters: Mark move operations noexcept so containers use move instead of copy during reallocation.

    📋 Quick Reference

    ConceptSyntax
    Rvalue referenceT&& r = move(x);
    Forwarding reftemplate<typename T> void f(T&& x)
    Perfect forwardforward<T>(x)
    Cast to rvaluemove(x)
    Guarantee elisionreturn T(args); (C++17)

    Lesson Complete!

    You now understand the deep mechanics of move semantics, perfect forwarding, and copy elision. Next: RAII Architecture — applying resource ownership patterns across complex systems.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service