Copy-on-Write Idiom

Saw on this roadmap https://roadmap.sh/cpp

Apparently, the kernel also does a copy-on-write idiom:

3) Round 3: Low-level: fork + printf/flush

These are classic “OS internals” landmines. Here’s the mental model you want ready.

How fork() works (what to say)

  • fork() creates a new process that is (almost) a duplicate of the parent.
  • The kernel creates a new process/task structure (PID, registers, file descriptor table refs, etc.).
  • Memory is not literally copied immediately: it’s copy-on-write (COW):
    • parent and child initially share the same physical pages
    • pages are marked read-only
    • on write, a page fault triggers a private copy for the writer
  • Return values:
    • parent gets child PID
    • child gets 0
    • on failure, returns -1 in parent

Extra credit:

  • open file descriptors are copied as references (shared open-file description), so they share file offsets unless you dup separately.
  • exec() replaces the child’s address space with a new program (common pattern: fork() then exec()).

Everyone has a single shared copy of the same data until it’s written, and then a copy is made.

Example (taken from roadmap):

#include <iostream>
#include <memory>
 
class MyString {
public:
    MyString(const std::string &str) : data(std::make_shared<std::string>(str)) {}
 
    // Use the same shared data for copying.
    MyString(const MyString &other) : data(other.data) { 
        std::cout << "Copied using the Copy-Write idiom." << std::endl;
    }
 
    // Make a copy only if we want to modify the data.
    void write(const std::string &str) {
        // Check if there's more than one reference.
        if (data.use_count() > 1) {
            data = std::make_shared<std::string>(*data);
            std::cout << "Copy is actually made for writing." << std::endl;
        }
        *data = str;
    }
 
private:
    std::shared_ptr<std::string> data;
};
 
int main() {
    MyString str1("Hello");
    MyString str2 = str1; // No copy operation, just shared references.
 
    str1.write("Hello, World!"); // This is where the actual duplication happens.
    return 0;
}

Pretty cool!