Title
unique_ptr update
Status
cd1
Section
[unique.ptr]
Submitter
Howard Hinnant

Created on 2007-05-04.00:00:00 last changed 163 months ago

Messages

Date: 2010-10-21.18:28:33

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

  • Change [unique.ptr.single]:

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

    Change [unique.ptr.single.observers]:

    T& typename add_lvalue_reference<T>::type operator*() const;
    
  • Change [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 [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 [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 [unique.ptr.single.observers]:

    T* pointer operator->() const;

    ...

    T* pointer get() const;

    Change [unique.ptr.single.modifiers]:

    T* pointer release();

    ...

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

    Change [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 [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 [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 [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).

Date: 2010-10-21.18:28:33

[ 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;
Date: 2010-10-21.18:28:33

[ 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. ]

Date: 2011-04-25.21:37:53

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!
    
History
Date User Action Args
2010-10-21 18:28:33adminsetmessages: + msg3396
2010-10-21 18:28:33adminsetmessages: + msg3395
2010-10-21 18:28:33adminsetmessages: + msg3394
2007-05-04 00:00:00admincreate