I want to implement my own observer_ptr
class which I want to use to indicate no ownership of a pointer. I'm wondering if it'd be possible to somehow prevent someone from using the following syntax:
observer_ptr<T> var_name(new T);
since it would completely invalidate the whole purpose of this class and lead to memory leaks. My guess would be that I would have to delete/make private a certain type of constructor, but I don't know what argument type I should choose to achieve that.
I'm not writing any sharable library, I'm asking more for myself so I can learn.
If you accept the input T*
pointer by a non-const reference, users can't call new
directly in the constructor call, as the reference won't be able to bind to the temporary that new
returns, eg:
template <typename T>
class observer_ptr
{
public:
observer_ptr(T*& ptr);
...
};
observer_ptr<T> var_name(new T); // error!
They would be required to use a local T*
variable instead, making them more aware of their responsibility for the lifetime of the object they create, eg:
T *ptr = new T;
observer_ptr<T> var_name(ptr); // OK!
Note, however, that this approach does prevent users from being able to directly observe non-dynamic objects whose addresses are taken by operator&
or std::addressof()
, as well as unique_ptr
and shared_ptr
objects, eg:
T obj;
observer_ptr<T> var_name(&obj); // error!
auto ptr = make_unique<T>(); // or make_shared()
observer_ptr<T> var_name(ptr.get()); // error!
This would also require the use of a local T*
pointer, eg:
T obj;
T* ptr = &obj;
observer_ptr<T> var_name(ptr); // OK!
auto obj = make_unique<T>(); // or make_shared()
T* ptr = obj.get();
observer_ptr<T> var_name(ptr); // OK!
You can avoid that if you add some additional constructors to observer_ptr
, eg:
template <typename T>
class observer_ptr
{
private:
T* m_ptr;
public:
observer_ptr(T*& ptr) : m_ptr(ptr) {}
observer_ptr(T& obj) : m_ptr(addressof(obj)) {}
observer_ptr(const unique_ptr<T>& ptr) : m_ptr(ptr.get()) {}
observer_ptr(const shared_ptr<T>& ptr) : m_ptr(ptr.get()) {}
observer_ptr(unique_ptr<T>&&) = delete;
observer_ptr(shared_ptr<T>&&) = delete;
...
};
T obj;
observer_ptr<T> var_name(obj); // OK!
auto ptr = make_unique<T>(); // or make_shared()
observer_ptr<T> var_name(ptr); // OK!
observer_ptr<T> var_name(make_unique<T>()); // error!
observer_ptr<T> var_name(make_shared<T>()); // error!