#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...