#include <algorithm>
#include <iostream>
#include <vector>

struct Device;
struct DeviceDependant;

struct DeviceDependant {
private:
	Device * device_;
public:
	DeviceDependant(Device &);
	DeviceDependant(DeviceDependant const &);
	DeviceDependant(DeviceDependant &&);
	~DeviceDependant();

	void onDeviceLost(Device * dev) {
		std::cout << "DeviceDependant::onDeviceLost() : this = " << (void*)this << ", dev = " << (void*)dev << std::endl;
	}

	void register_self();
	void unregister_self();
};

struct Device {
private:
	std::vector<DeviceDependant *> dependants_;
public:
	Device() = default;
	~Device() {
		notify_dependants();
	}

	void register_dependant(DeviceDependant * dep) {
		std::cout << "Device::register_dependant() : this = " << (void*)this << ", dep = " << (void*)dep << std::endl;
		dependants_.push_back(dep);
	}

	void unregister_dependant(DeviceDependant const * dep) {
		std::cout << "Device::unregister_dependant() : this = " << (void*)this << ", dep = " << (void*)dep << std::endl;
		dependants_.erase(
			std::remove_if(
				std::begin(dependants_),
				std::end(dependants_),
				[&](DeviceDependant const * local) { return (local == dep); }
			),
			std::end(dependants_)
		);
	}

	void notify_dependants() {
		for(auto & dep : dependants_) {
			dep->onDeviceLost(this);
		}
	}
};

DeviceDependant::DeviceDependant(Device & dev)
: device_(&dev) {
	register_self();
}

DeviceDependant::DeviceDependant(DeviceDependant const & dep)
: device_(dep.device_) {
	register_self();
}

DeviceDependant::DeviceDependant(DeviceDependant && dep)
: device_(nullptr) {
	dep.unregister_self();
	std::swap(device_, dep.device_);
	register_self();
}

DeviceDependant::~DeviceDependant() {
	if(device_) {
		device_->unregister_dependant(this);
	}
}

void DeviceDependant::register_self() {
	if(device_) {
		device_->register_dependant(this);
	}
}

void DeviceDependant::unregister_self() {
	if(device_) {
		device_->unregister_dependant(this);
	}
}

int main(int argc, char ** argv) {
	Device dev;
	DeviceDependant dep1(dev);
	DeviceDependant dep2(dev);
	{
		DeviceDependant dep3(dev);
	}
	DeviceDependant dep4 = std::move(dep2);
	dev.notify_dependants();

	return 0;
}