−65% Most banks now $169 $59.
C++ coding · 10 min read

HRT's Copy-on-Write String C++ Question

Hudson River Trading interviews lean hard on C++ internals. This copy-on-write string is a recurring on-site and phone question that quietly tests reference counting, value semantics, and the subtleties of sharing memory between instances, then makes you reason about threads. Here is the full question, C++ for each stage, and a detailed rubric.


The question

Implement a copy-on-write string class in C++. Multiple instances can share one underlying buffer; a modification copies the buffer only if it is currently shared; reference counts are tracked. Implement the constructor, copy constructor, assignment operator, operator[] in both const and non-const forms, and c_str.

Bonus: make it thread-safe.

Stage 1 · Shared buffer with reference counting

Put the character data and a reference count in one heap block. Copies share that block and bump the count; destruction drops it and frees only at zero. This gives cheap copies and correct lifetime.

#include <cstring>
#include <cstddef>

class CowString {
    struct Buffer {
        size_t refs;
        size_t len;
        char   data[1];   // flexible-array-style trailing storage
    };
    Buffer* buf_;

    static Buffer* alloc(const char* s, size_t len) {
        Buffer* b = static_cast<Buffer*>(::operator new(sizeof(Buffer) + len));
        b->refs = 1;
        b->len  = len;
        std::memcpy(b->data, s, len);
        b->data[len] = '\0';
        return b;
    }
    void release() { if (buf_ && --buf_->refs == 0) ::operator delete(buf_); }

public:
    CowString(const char* s = "") : buf_(alloc(s, std::strlen(s))) {}

    CowString(const CowString& other) : buf_(other.buf_) { ++buf_->refs; }   // share, do not copy

    CowString& operator=(const CowString& other) {
        if (this != &other) {
            ++other.buf_->refs;   // guard self-assignment by incrementing first
            release();
            buf_ = other.buf_;
        }
        return *this;
    }

    ~CowString() { release(); }

    const char* c_str() const { return buf_->data; }
};

Stage 2 · Copy on mutation

Const access can hand back a reference into the shared buffer. Non-const access might be used to write, so it must detach first: if the buffer is shared, deep-copy it into a private one before returning a mutable reference. That is the whole point of copy-on-write.

    // Detach: if the buffer is shared, make a private copy before mutating.
    void detach() {
        if (buf_->refs > 1) {
            Buffer* fresh = alloc(buf_->data, buf_->len);
            --buf_->refs;        // we still hold a reference to the old one
            buf_ = fresh;
        }
    }

    char  operator[](size_t i) const { return buf_->data[i]; }      // read: no copy

    char& operator[](size_t i) {       // write path: must own the buffer first
        detach();
        return buf_->data[i];
    }

The trap is returning a non-const reference without detaching: a write through it would corrupt every instance sharing the buffer. Note too that the non-const operator pessimistically copies even for a read, which is the known cost of this design.

Stage 3 · Thread safety

An atomic reference count is necessary but not sufficient. It makes share and release race-free, but two threads mutating views of the same logical string still need higher-level synchronization, and detach must atomically check-and-copy.

#include <atomic>

struct Buffer {
    std::atomic<size_t> refs;   // atomic so share/release are race-free
    size_t len;
    char   data[1];
};

// release becomes:
void release() {
    if (buf_ && buf_->refs.fetch_sub(1, std::memory_order_acq_rel) == 1)
        ::operator delete(buf_);
}

Say the quiet part: atomics protect the refcount, not the bytes. Concurrent writers to the same string need a mutex or a redesign, and the read-then-copy in detach has a race unless the count check and the copy are made atomic together.

How HRT scores it

Dimension Weak Strong
Reference countingLeaks or double-frees on copy or assignOne refcount per buffer, freed exactly at zero
Self-assignmentFrees then reads freed memoryIncrements before releasing, or checks identity
Copy-on-writeCopies eagerly or neverCopies only when shared, and only on the write path
const vs non-constBoth accessors behave the sameconst reads shared data, non-const detaches first
Memory safetyOff-by-one on the null terminatorCorrect sizing and termination, no UB
Thread safetyClaims an atomic refcount is enoughAtomic count plus an honest account of writer races

This is one question of 12 pages

Get the full Hudson River Trading question bank

The full HRT bank is heavy on C++ systems internals: copy-on-write, std::function, lock-free structures, and memory ordering, each with follow-ups and a rubric, compiled from people familiar with the process and cross-verified across sources.

Hudson River Trading interview FAQ

What does the Hudson River Trading interview ask?+

Deep C++ systems questions: implement copy-on-write, std::function, or a lock-free stack, plus memory ordering, atomics, scheduling, and deadlock. The signal is precise reasoning about value semantics, ownership, and concurrency, not algorithmic tricks.

Do I need C++ for the HRT interview?+

For core engineering roles, effectively yes. HRT's questions are framed in C++ and probe its memory model, RAII, smart pointers, atomics, and the standard library internals. Comfort with these is expected.

What makes the copy-on-write string question hard?+

Getting the reference counting exactly right across the constructor, copy constructor, and assignment, then realizing that a non-const accessor must detach a shared buffer before returning a mutable reference, and that making it thread-safe needs more than an atomic refcount.

How is the HRT coding round scored?+

On correct shared-buffer reference counting, copy-on-write only when shared, const versus non-const access semantics, no leaks or double frees, and an honest account of what thread safety actually requires.

Where can I find real Hudson River Trading interview questions?+

Pichup maintains an HRT question bank compiled from people familiar with the process, with the C++ systems questions, their follow-ups, and rubrics. The question in this guide is one of them.