2

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; }; 
4
  • 1
    The same is true for the real unique_ptr. But to answer your specific question - you can't do anything, reliably/portably (at least not last time I was familiar with C++). Commented Apr 9, 2017 at 23:00
  • 1
    You could have a flag which controls whether you call delete or not, and set it when creating a unique_ptr on a stack allocated object. It does of course beg the question why you're creating unique_ptrs to stack allocated objects in the first place Commented Apr 9, 2017 at 23:02
  • This doesn't make sense. The point of a unique_ptr is that it is the sole owner of the resource. If the stack owns it, then a unique_ptr shouldn't point to it. Commented Apr 9, 2017 at 23:18
  • @Galik "Doesn't make sense" is not an excuse to not be thorough. Commented Apr 9, 2017 at 23:19

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.