#include <iostream>

struct mutex {
    void acquire() { std::cout << "Mutex acquired.\n"; }
    void release() { std::cout << "Mutex released.\n"; }
};

template <typename T>
struct locker_box {
    struct cookie {
        cookie() : b(nullptr) {}
        cookie(locker_box& b) : b(&b) {}

        T& operator*() {
            return b->t;
        }
        T* operator->() {
            return b->t;
        }
        cookie& operator++() {
            b = nullptr;
            return *this;
        }
        cookie operator++(int) {
            cookie copy(*this);
            operator++();
            return copy;
        }
        bool operator==(cookie const& c) {
            return b == c.b;
        }
        bool operator!=(cookie const& c) {
            return b != c.b;
        }
    private:
        locker_box* b;
    };
    struct open_box {
        open_box(locker_box& b) : b(b) { b.m.acquire(); }
        ~open_box() { b.m.release(); }
        cookie begin() { return cookie(b); }
        cookie end() { return cookie(); }
    private:
        locker_box& b;
    };

    open_box open() {
        return open_box(*this);
    }

private:
    friend class open_box;
    friend class cookie;
    mutex m;
    T t;
};

struct not_suitable_for_this_audience {};

struct racy {
    void do_racy_stuff() { std::cout << "Being racy...\n"; }
    void do_more_racy_stuff() { std::cout << "Being even more racy...\n"; }
    void do_really_raunchy_stuff() { throw not_suitable_for_this_audience(); }
};

int main() {
    locker_box<racy> box;
    try {
        for(auto& x : box.open()) {
            x.do_racy_stuff();
            x.do_more_racy_stuff();
            x.do_really_raunchy_stuff();
        }
    } catch(not_suitable_for_this_audience const&) {
        std::cout << "Ooops..."
    }
}

// This prints:
// Mutex acquired.
// Being racy...
// Being even more racy...
// Mutex released.
// Ooops...