Moving transfers ownership from one object to another.

move `std::move` allows movable objects such as `std::unique_ptr` to transfer ownership.

Move Semantics

name
move_semantics.cpp
Replay: real traced execution (multi-file project)
#include <iostream>
#include <memory>
#include <string>

int main() {
    std::string name = "cache";

    std::unique_ptr<std::string> original = std::make_unique<std::string>(name);
    std::unique_ptr<std::string> moved = std::move(original);

    std::cout << "originalEmpty=" << (original == nullptr) << std::endl;
    std::cout << "movedValue=" << *moved << std::endl;
    return 0;
}
#include <iostream>
#include <memory>
#include <string>

int main() {
    std::string name = "report";

    std::unique_ptr<std::string> original = std::make_unique<std::string>(name);
    std::unique_ptr<std::string> moved = std::move(original);

    std::cout << "originalEmpty=" << (original == nullptr) << std::endl;
    std::cout << "movedValue=" << *moved << std::endl;
    return 0;
}
#include <iostream>
#include <memory>
#include <string>

int main() {
    std::string name = "token";

    std::unique_ptr<std::string> original = std::make_unique<std::string>(name);
    std::unique_ptr<std::string> moved = std::move(original);

    std::cout << "originalEmpty=" << (original == nullptr) << std::endl;
    std::cout << "movedValue=" << *moved << std::endl;
    return 0;
}
  1. name ← cache, original ← (empty), moved ← (empty)

    5int main() {6    std::string name→ cache = "cache"; //@name="report", "token"78    std::unique_ptr<std::string> original→ (empty) = std::make_unique<std::string>(namecache);9    std::unique_ptr<std::string> moved→ (empty) = std::move(original(empty));1011    std::cout << "originalEmpty=" << (original(empty) == nullptr) << std::endl;12    std::cout << "movedValue=" << *moved(empty) << std::endl;13    return 0;14}
    outputoriginalEmpty=1
    movedValue=cache
  1. name ← report, original ← (empty), moved ← (empty)

    5int main() {6    std::string name→ report = "report";78    std::unique_ptr<std::string> original→ (empty) = std::make_unique<std::string>(namereport);9    std::unique_ptr<std::string> moved→ (empty) = std::move(original(empty));1011    std::cout << "originalEmpty=" << (original(empty) == nullptr) << std::endl;12    std::cout << "movedValue=" << *moved(empty) << std::endl;13    return 0;14}
    outputoriginalEmpty=1
    movedValue=report
  1. name ← token, original ← (empty), moved ← (empty)

    5int main() {6    std::string name→ token = "token";78    std::unique_ptr<std::string> original→ (empty) = std::make_unique<std::string>(nametoken);9    std::unique_ptr<std::string> moved→ (empty) = std::move(original(empty));1011    std::cout << "originalEmpty=" << (original(empty) == nullptr) << std::endl;12    std::cout << "movedValue=" << *moved(empty) << std::endl;13    return 0;14}
    outputoriginalEmpty=1
    movedValue=token

Follow the Move

  1. name starts as cache.
  2. original owns a heap string with value cache.
  3. std::move(original) transfers that ownership into moved.
  4. original becomes empty, so original == nullptr prints 1.
  5. moved now owns the string, so *moved prints cache. | name | before move owner | after move owner | originalEmpty | movedValue | | --- | --- | --- | ---: | --- | | cache | original | moved | 1 | cache | | report | original | moved | 1 | report | | token | original | moved | 1 | token |

Exercise: move_semantics.cpp

Reproduce originalEmpty=1 and movedValue=cache, then use names report and token to predict the movedValue line.