This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of CD1 status.

### 673. `unique_ptr` update

Section: 20.11.1 [unique.ptr] Status: CD1 Submitter: Howard Hinnant Opened: 2007-05-04 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [unique.ptr].

View all issues with CD1 status.

Discussion:

Since the publication of N1856 there have been a few small but significant advances which should be included into `unique_ptr`. There exists a example implementation for all of these changes.

- Even though `unique_ptr<void>` is not a valid use case (unlike for `shared_ptr<void>`), unexpected cases to crop up which require the instantiation of the interface of `unique_ptr<void>` even if it is never used. For example see 541 for how this accidently happened to `auto_ptr`. I believe the most robust way to protect `unique_ptr` against this type of failure is to augment the return type of `unique_ptr<T>:operator*()` with `add_lvalue_reference<T>::type`. This means that given an instantiated `unique_ptr<void>` the act of dereferencing it will simply return `void` instead of causing a compile time failure. This is simpler than creating a `unique_ptr<void>` specialization which isn't robust in the face of `cv-`qualified `void` types.

  This resolution also supports instantiations such as `unique_ptr<void, free_deleter>` which could be very useful to the client.

- Efforts have been made to better support containers and smart pointers in shared memory contexts. One of the key hurdles in such support is not assuming that a pointer type is actually a `T*`. This can easily be accomplished for `unique_ptr` by having the deleter define the pointer type: `D::pointer`. Furthermore this type can easily be defaulted to `T*` should the deleter `D` choose not to define a pointer type (example implementation here). This change has no run time overhead. It has no interface overhead on authors of custom delter types. It simply allows (but not requires) authors of custom deleter types to define a smart pointer for the storage type of `unique_ptr` if they find such functionality useful. `std::default_delete` is an example of a deleter which defaults `pointer` to `T*` by simply ignoring this issue and not including a `pointer typedef`.

- When the deleter type is a function pointer then it is unsafe to construct a `unique_ptr` without specifying the function pointer in the constructor. This case is easy to check for with a `static_assert` assuring that the deleter is not a pointer type in those constructors which do not accept deleters.

  >     unique_ptr<A, void(*)(void*)> p(new A);  // error, no function given to delete the pointer!

[ Kona (2007): We don't like the solution given to the first bullet in light of concepts. The second bullet solves the problem of supporting fancy pointers for one library component only. The full LWG needs to decide whether to solve the problem of supporting fancy pointers piecemeal, or whether a paper addressing the whole library is needed. We think that the third bullet is correct. ]

[ Post Kona: Howard adds example user code related to the first bullet: ]

>     void legacy_code(void*, std::size_t);

>     void foo(std::size_t N)
>     {
>         std::unique_ptr<void, void(*)(void*)> ptr(std::malloc(N), std::free);
>         legacy_code(ptr.get(), N);
>     }   // unique_ptr used for exception safety purposes

I.e. `unique_ptr<void>` is a useful tool that we don't want to disable with concepts. The only part of `unique_ptr<void>` we want to disable (with concepts or by other means) are the two member functions:

>     T& operator*() const;
>     T* operator->() const;

Proposed resolution:

[ I am grateful for the generous aid of Peter Dimov and Ion Gaztañaga in helping formulate and review the proposed resolutions below. ]

- Change 20.11.1.3 [unique.ptr.single]:

  >     template <class T, class D = default_delete<T>> class unique_ptr {
  >        ...
  >        T& typename add_lvalue_reference<T>::type operator*() const;
  >        ...
  >     };

  Change 20.11.1.3.5 [unique.ptr.single.observers]:

  >     T& typename add_lvalue_reference<T>::type operator*() const;

- Change 20.11.1.3 [unique.ptr.single]:

  >     template <class T, class D = default_delete<T>> class unique_ptr {
  >     public:
  >       typedef implementation (see description below) pointer;
  >        ...
  >        explicit unique_ptr(T* pointer p);
  >        ...
  >        unique_ptr(T* pointer p, implementation defined (see description below) d);
  >        unique_ptr(T* pointer p, implementation defined (see description below) d);
  >        ...
  >        T* pointer operator->() const;
  >        T* pointer get() const;
  >        ...
  >        T* pointer release();
  >        void reset(T* pointer p = 0 pointer());
  >     };

  -3- If the type `remove_reference<D>::type::pointer` exists, then `unique_ptr<T, D>::pointer` is a typedef to `remove_reference<D>::type::pointer`. Otherwise `unique_ptr<T, D>::pointer` is a typedef to `T*`. The type `unique_ptr<T, D>::pointer` shall be `CopyConstructible` and `CopyAssignable`.

  Change 20.11.1.3.2 [unique.ptr.single.ctor]:

  >     unique_ptr(T* pointer p);
  >     ...
  >     unique_ptr(T* pointer p, implementation defined d);
  >     unique_ptr(T* pointer p, implementation defined d);
  >     ...
  >     unique_ptr(T* pointer p, const A& d);
  >     unique_ptr(T* pointer p, A&& d);
  >     ...
  >     unique_ptr(T* pointer p, A& d);
  >     unique_ptr(T* pointer p, A&& d);
  >     ...
  >     unique_ptr(T* pointer p, const A& d);
  >     unique_ptr(T* pointer p, const A&& d);
  >     ...

  -23- Requires: If `D` is not a reference type, construction of the deleter `D` from an rvalue of type `E` must shall be well formed and not throw an exception. If `D` is a reference type, then `E` must shall be the same type as `D` (diagnostic required). `U*` `unique_ptr<U,E>::pointer` must shall be implicitly convertible to `T*` pointer.

  -25- Postconditions: `get() == value u.get()` had before the construction, modulo any required offset adjustments resulting from the cast from `U*` `unique_ptr<U,E>::pointer` to `T*` pointer. `get_deleter()` returns a reference to the internally stored deleter which was constructed from `u.get_deleter()`.

  Change 20.11.1.3.4 [unique.ptr.single.asgn]:

  > -8- Requires: Assignment of the deleter `D` from an rvalue `D` must shall not throw an exception. `U*` `unique_ptr<U,E>::pointer` must shall be implicitly convertible to `T*` pointer.

  Change 20.11.1.3.5 [unique.ptr.single.observers]:

  >     T* pointer operator->() const;

  > ...

  >     T* pointer get() const;

  Change 20.11.1.3.6 [unique.ptr.single.modifiers]:

  >     T* pointer release();

  > ...

  >     void reset(T* pointer p = 0 pointer());

  Change 20.11.1.4 [unique.ptr.runtime]:

  >     template <class T, class D> class unique_ptr<T[], D> {
  >     public:
  >       typedef implementation pointer;
  >        ...
  >        explicit unique_ptr(T* pointer p);
  >        ...
  >        unique_ptr(T* pointer p, implementation defined d);
  >        unique_ptr(T* pointer p, implementation defined d);
  >        ...
  >        T* pointer get() const;
  >        ...
  >        T* pointer release();
  >        void reset(T* pointer p = 0 pointer());
  >     };

  Change 20.11.1.4.2 [unique.ptr.runtime.ctor]:

  >     unique_ptr(T* pointer p);
  >     unique_ptr(T* pointer p, implementation defined d);
  >     unique_ptr(T* pointer p, implementation defined d);

  > These constructors behave the same as in the primary template except that they do not accept pointer types which are convertible to `T*` `pointer`. [Note: One implementation technique is to create private templated overloads of these members. -- end note]

  Change 20.11.1.4.5 [unique.ptr.runtime.modifiers]:

  >     void reset(T* pointer p = 0 pointer());

  > -1- Requires: Does not accept pointer types which are convertible to `T*` `pointer` (diagnostic required). [Note: One implementation technique is to create a private templated overload. -- end note]

- Change 20.11.1.3.2 [unique.ptr.single.ctor]:

  >     unique_ptr();

  > > Requires: `D` must shall be default constructible, and that construction must shall not throw an exception. `D` must shall not be a reference type or pointer type (diagnostic required).

  >     unique_ptr(T* pointer p);

  > > Requires: The expression `D()(p)` must shall be well formed. The default constructor of `D` must shall not throw an exception. `D` must shall not be a reference type or pointer type (diagnostic required).