Created
September 10, 2019 05:20
-
-
Save SF-Zhou/daa839865468feecab7431ab875455c6 to your computer and use it in GitHub Desktop.
Rust-like Ownership and Reference
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <atomic> | |
#include <cassert> | |
#include <iostream> | |
using namespace std; | |
template <class T> | |
class MutableRef; | |
template <class T> | |
class ImmutableRef; | |
template <class T> | |
class OwnerPointer { | |
private: | |
T *rep_ = nullptr; | |
atomic<int> ref_; | |
public: | |
OwnerPointer(T *rep = nullptr) : rep_(rep), ref_(0) {} | |
~OwnerPointer() { delete rep_; } | |
OwnerPointer(const OwnerPointer<T> &other) = delete; | |
OwnerPointer(OwnerPointer<T> &&other) { swap(rep_, other.rep_); } | |
operator T *() { return rep_; } | |
OwnerPointer &operator=(const OwnerPointer<T> &other) = delete; | |
OwnerPointer &operator=(OwnerPointer<T> &&other) { | |
swap(rep_, other.rep_); | |
return *this; | |
} | |
MutableRef<T> RefMutable(); | |
ImmutableRef<T> RefImmutable(); | |
private: | |
friend class MutableRef<T>; | |
void UnrefMutable() { ++ref_; } | |
friend class ImmutableRef<T>; | |
void UnrefImmutable() { --ref_; } | |
}; | |
template <class T> | |
class ImmutableRef { | |
private: | |
OwnerPointer<T> *rep_; | |
private: | |
friend class OwnerPointer<T>; | |
ImmutableRef(OwnerPointer<T> *rep) : rep_(rep) {} | |
public: | |
~ImmutableRef() { rep_->UnrefImmutable(); } | |
operator const T *() { return rep_->rep_; } | |
}; | |
template <class T> | |
class MutableRef { | |
private: | |
OwnerPointer<T> *rep_; | |
private: | |
friend class OwnerPointer<T>; | |
MutableRef(OwnerPointer<T> *rep) : rep_(rep) {} | |
public: | |
~MutableRef() { rep_->UnrefMutable(); } | |
operator T *() { return rep_->rep_; } | |
}; | |
template <class T> | |
ImmutableRef<T> OwnerPointer<T>::RefImmutable() { | |
assert(ref_ >= 0); | |
++ref_; | |
return ImmutableRef<T>(this); | |
} | |
template <class T> | |
MutableRef<T> OwnerPointer<T>::RefMutable() { | |
assert(ref_ == 0); | |
--ref_; | |
return MutableRef<T>(this); | |
} | |
template <class T, class... Args> | |
OwnerPointer<T> make_owner(Args &&... args) { | |
return OwnerPointer<T>(new T(std::forward<Args>(args)...)); | |
} | |
int main() { | |
auto owner1 = make_owner<int>(20); | |
printf("Owner1: %d\n", *owner1); | |
auto owner2 = std::move(owner1); | |
printf("Owner2: %d\n", *owner2); | |
OwnerPointer<int> owner3; | |
owner3 = std::move(owner2); | |
printf("Owner3: %d\n", *owner3); | |
{ | |
auto immutable1 = owner3.RefImmutable(); | |
printf("Immutable1: %d\n", *immutable1); | |
// *immutable1 = 30; // Err | |
auto immutable2 = owner3.RefImmutable(); | |
printf("Immutable2: %d\n", *immutable2); | |
} | |
{ | |
auto mutable1 = owner3.RefMutable(); | |
printf("Mutable1: %d\n", *mutable1); | |
*mutable1 = 30; // Err | |
printf("Mutable1: %d\n", *mutable1); | |
// auto immutable1 = owner3.RefImmutable(); // Err | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment