Alden Bernitt
Alden Bernitt

Reputation: 139

Implementing unique_ptr: Deleting non-allocated objects

My goal here is to implement a simple version of unique_ptr which offers only a constructor, destructor, ->, *, and release().

However, I don't know what to do in the case where a unique_ptr is initialized using a non-allocated pointer.

eg

int i = 0;
unique_ptr<int> p{&i};

If the unique_ptr simply calls delete on it owned pointer, this will produced undefined (and undesirable) behavior, at least as far as I know. What can I do to prevent this?

EDIT: My attempt at the problem is as follows...

template<typename T>
class Uptr
{
public:
    Uptr<T>(T* pt) : mp_owned{pt} {}
    ~Uptr<T>() {delete mp_owned;}

    Uptr<T>(const Uptr<T>&) = delete;
    Uptr<T>& operator=(const Uptr<T>&) = delete;

    T& operator*() const {return *mp_owned;}
    T* operator->() const {return mp_owned;}

    T* release() {return mp_owned;}

private:
    T* mp_owned;
};

Upvotes: 2

Views: 158

Answers (2)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727047

Unfortunately, there is nothing you can do about this: the ownership of the object must be transferred to unique_ptr<T>, which is not possible if you use addresses of objects in global, static, or automatic areas.

The implementation from the standard library, i.e. std::unique_ptr<T,Deleter>, takes a deleter parameter, which you can use to not delete anything. However, this use is highly questionable, because in this situation you do not need unique_ptr at all.

Upvotes: 2

Kerrek SB
Kerrek SB

Reputation: 477580

You cannot check programmatically how a pointer value was obtained. In your situation (which is highly representative of large parts of real programming!), the solution is to document your interface to require that the pointer value be deletable. You place a precondition on your users, which requires that your users read the documentation and follow it, and you do not and cannot provide in-language methods for validating those preconditions. You pass the burden on to your users.

Such precondition burdens always form a kind of "technical debt", and you want to avoid it as much as you can (but perhaps not at the expense of runtime cost). For example, in the standard library we would strongly discourage the use of the ownership-taking constructor of unique_ptr and instead as the user to use make_unique, which has no preconditions and results in a valid unique_ptr value. That design is exemplary for how you would manage technical debt in the real world.

Upvotes: 4

Related Questions