CodeNebula
C++14stlintermediate

std::exchange

C++14 · Modern Refined · Compiler flag: -std=c++14

Explanation

Replaces the value of an object with a new value and returns the old value in a single atomic-looking expression. It simplifies move constructors, state-machine transitions, and any pattern where you need the previous state before overwriting it.

Real-World Scenario

A state machine for a network connection transitions between states. `std::exchange` captures the previous state for logging while atomically updating to the new state.

Quick Snippet

snippet.cpp
#include <utility>
#include <iostream>
#include <string>

enum class State { Idle, Connecting, Connected, Disconnected };

const char* to_string(State s) {
    switch (s) {
        case State::Idle:         return "Idle";
        case State::Connecting:   return "Connecting";
        case State::Connected:    return "Connected";
        case State::Disconnected: return "Disconnected";
    }
    return "Unknown";
}

int main() {
    State current = State::Idle;

    State prev = std::exchange(current, State::Connecting);
    std::cout << to_string(prev) << " -> " << to_string(current) << "\n";
    // Idle -> Connecting

    prev = std::exchange(current, State::Connected);
    std::cout << to_string(prev) << " -> " << to_string(current) << "\n";
    // Connecting -> Connected
}

Full Example

exchange.cpp
// CodeNebula - C++14 Example: std::exchange
// Compile: g++ -std=c++14 -Wall -Wextra -o example exchange.cpp

// Demonstrates std::exchange which replaces a variable's value and returns
// the old value in one atomic-style operation. Real-world use: move
// constructors/assignment, state machines, linked list operations,
// and any "swap-and-return-old" pattern.

#include <iostream>
#include <utility>
#include <string>
#include <vector>
#include <memory>

// ------------------------------------------------------------------
// 1. Using exchange in a move constructor (classic pattern)
// ------------------------------------------------------------------
class Buffer
{
    int* data_;
    std::size_t size_;

public:
    Buffer(std::size_t size)
        : data_(new int[size]), size_(size)
    {
        for (std::size_t i = 0; i < size; ++i)
            data_[i] = static_cast<int>(i * 10);
    }

    // Move constructor using std::exchange for clean resource transfer
    Buffer(Buffer&& other) noexcept
        : data_(std::exchange(other.data_, nullptr))
        , size_(std::exchange(other.size_, 0))
    {}

    ~Buffer() { delete[] data_; }

    void print() const
    {
        std::cout << "  Buffer[size=" << size_ << "]: ";
        if (data_)
        {
            for (std::size_t i = 0; i < size_; ++i)
                std::cout << data_[i] << " ";
        }
        else
        {
            std::cout << "(empty/moved-from)";
        }
        std::cout << std::endl;
    }
};

// ------------------------------------------------------------------
// 2. State machine using exchange
// ------------------------------------------------------------------
enum class State { Idle, Running, Paused, Stopped };

const char* state_name(State s)
{
    switch (s)
    {
        case State::Idle:    return "Idle";
        case State::Running: return "Running";
        case State::Paused:  return "Paused";
        case State::Stopped: return "Stopped";
    }
    return "Unknown";
}

int main()
{
    // ------------------------------------------------------------------
    // 1. Basic exchange - swap and get old value
    // ------------------------------------------------------------------
    std::cout << "=== Basic std::exchange ===" << std::endl;
    int value = 42;
    int old = std::exchange(value, 100);
    std::cout << "  old value: " << old << std::endl;
    std::cout << "  new value: " << value << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 2. Exchange with strings
    // ------------------------------------------------------------------
    std::cout << "=== String Exchange ===" << std::endl;
    std::string name = "Alice";
    std::string prev = std::exchange(name, "Bob");
    std::cout << "  previous: " << prev << std::endl;
    std::cout << "  current : " << name << std::endl;
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 3. Move constructor pattern
    // ------------------------------------------------------------------
    std::cout << "=== Move Constructor with exchange ===" << std::endl;
    Buffer original(5);
    std::cout << "  Before move:" << std::endl;
    original.print();

    Buffer moved(std::move(original));
    std::cout << "  After move (new):" << std::endl;
    moved.print();
    std::cout << "  After move (old):" << std::endl;
    original.print();
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 4. State machine transitions
    // ------------------------------------------------------------------
    std::cout << "=== State Machine Transitions ===" << std::endl;
    State current = State::Idle;

    auto transition = [&current](State next) {
        State prev = std::exchange(current, next);
        std::cout << "  " << state_name(prev) << " -> "
                  << state_name(current) << std::endl;
    };

    transition(State::Running);
    transition(State::Paused);
    transition(State::Running);
    transition(State::Stopped);
    std::cout << std::endl;

    // ------------------------------------------------------------------
    // 5. Building a history / undo stack
    // ------------------------------------------------------------------
    std::cout << "=== Building History with exchange ===" << std::endl;
    std::vector<int> history;
    int counter = 0;

    for (int new_val : {10, 20, 30, 40})
    {
        int old_val = std::exchange(counter, new_val);
        history.push_back(old_val);
    }

    std::cout << "  Current: " << counter << std::endl;
    std::cout << "  History:";
    for (int h : history)
        std::cout << " " << h;
    std::cout << std::endl;

    return 0;
}

/*
Expected output:

=== Basic std::exchange ===
  old value: 42
  new value: 100

=== String Exchange ===
  previous: Alice
  current : Bob

=== Move Constructor with exchange ===
  Before move:
  Buffer[size=5]: 0 10 20 30 40
  After move (new):
  Buffer[size=5]: 0 10 20 30 40
  After move (old):
  Buffer[size=0]: (empty/moved-from)

=== State Machine Transitions ===
  Idle -> Running
  Running -> Paused
  Paused -> Running
  Running -> Stopped

=== Building History with exchange ===
  Current: 40
  History: 0 10 20 30
*/
Run command
g++ -std=c++14 -Wall -Wextra -o example exchange.cpp