#include template struct const_ref; template struct mut_ref; struct unsafe_op {}; template struct safe_ptr { long refcnt; T *data; safe_ptr() : refcnt(0), data(new T) {} safe_ptr(T val) : refcnt(0), data(new T) { *data = val; } ~safe_ptr() { delete data; } safe_ptr(safe_ptr const&) = delete; const_ref operator &() { if (refcnt >= 0) return const_ref{this}; else throw unsafe_op{}; } mut_ref operator +() { if (refcnt == 0) return mut_ref{this}; else throw unsafe_op{}; } }; template struct const_ref { safe_ptr& ptr; const_ref(safe_ptr *upstream) : ptr(*upstream) { ptr.refcnt += 1; } ~const_ref() { ptr.refcnt -= 1; } T const& operator *() { return *ptr.data; } }; template struct mut_ref { safe_ptr& ptr; mut_ref(safe_ptr *upstream) : ptr(*upstream) { ptr.refcnt -= 1; } ~mut_ref() { ptr.refcnt += 1; } T& operator *() { return *ptr.data; } }; int main() { safe_ptr x { 1 }; { auto ref = &x; // *ref = 100; // would fail for modification of const auto ref2 = &x; printf("%i", *ref, *ref2); // auto mut_ref = +x; // would fail for taking mutable ref while const refs exist } { auto mut_ref = +x; *mut_ref = 10; } { auto ref = &x; printf("%i", *ref); } }