#include <memory>
#include <vector>
#include <functional>
#include <iostream>
#include <algorithm>
template<class T>
class observer_ptr;
template <typename T>
class observable_delete {
std::vector<observer_ptr<T>*> notifyList;
public:
void remove_observable(observer_ptr<T>* remove_this);
void add_observable(observer_ptr<T>* add_this);
void operator()(T* obj) const;
};
template <typename T>
class observer_ptr {
T* pt = nullptr;
observable_delete<T>* deleter;
bool has_callback;
std::function<void (T*)> callback;
public:
observer_ptr(const observer_ptr<T> &other) : pt(other.pt), deleter(other.deleter), has_callback(other.has_callback), callback(other.callback) {
deleter->add_observable(this);
}
observer_ptr(observer_ptr<T> &&other) : pt(other.pt), deleter(other.deleter), has_callback(other.has_callback), callback(std::move(other.callback)) {
deleter->remove_observable(&other);
other.pt = nullptr; //flags temporary as expired.
deleter->add_observable(this);
}
observer_ptr<T> operator=(const observer_ptr<T> &other) = delete;
observer_ptr(std::unique_ptr<T, observable_delete<T>>* observed) : pt(observed->get()), deleter(&observed->get_deleter()), has_callback(false) {
deleter->add_observable(this);
}
observer_ptr(std::unique_ptr<T, observable_delete<T>>* observed, const std::function<void(T*)> &callback) : pt(observed->get()), deleter(&observed->get_deleter()), callback(callback), has_callback(true) {
deleter->add_observable(this);
}
~observer_ptr() {
if (!expired()) {
deleter->remove_observable(this);
}
}
void observed_has_died() {
if (has_callback) {
callback(pt);
}
pt = nullptr;
}
bool expired() const {
return pt == nullptr;
}
T* operator->() const { return pt; }
T& operator*() const { return *pt; }
};
template <typename T>
void observable_delete<T>::remove_observable(observer_ptr<T>* remove_this) {
auto found = std::find(notifyList.begin(), notifyList.end(), remove_this);
if (found != notifyList.end()) {
notifyList.erase(found);
}
}
template <typename T>
void observable_delete<T>::add_observable(observer_ptr<T>* add_this) {
notifyList.push_back(add_this);
}
template <typename T>
void observable_delete<T>::operator()(T* obj) const {
for (auto&& item : notifyList) {
try {
item->observed_has_died();
} catch (...) {
delete obj;
throw;
}
}
delete obj;
}
template<typename T, typename... Args>
std::unique_ptr<T, observable_delete<T>> make_observable_unique(Args&&... args) {
return std::unique_ptr<T, observable_delete<T>>(new T(std::forward<Args>(args)...));
}
template<typename T>
observer_ptr<T> make_observer(std::unique_ptr<T, observable_delete<T>> &observed) {
return observer_ptr<T>(&observed);
}
template<typename T, typename F>
observer_ptr<T> make_observer(std::unique_ptr<T, observable_delete<T>> &observed, const F &callback) {
return observer_ptr<T>(&observed, callback);
}
int main() {
auto uniquePtrValue = make_observable_unique<int>(5);
auto observer = make_observer(uniquePtrValue, [](int *value) { std::cout << "We're destroying it! " << *value << std::endl; });
std::cout << (!observer.expired() ? *observer : -1) << std::endl;
uniquePtrValue.reset();
std::cout << (!observer.expired() ? *observer : -1) << std::endl;
return 0;
}