1297. unique_ptr's relational operator functions should induce a total order

Section: 23.11.1.5 [unique.ptr.special] Status: Resolved Submitter: Daniel Krügler Opened: 2009-12-23 Last modified: 2016-02-10

Priority: Not Prioritized

View all issues with Resolved status.

Discussion:

The comparison functions of unique_ptr currently directly delegate to the underlying comparison functions of unique_ptr<T, D>::pointer. This is disadvantageous, because this would not guarantee to induce a total ordering for native pointers and it is hard to define a total order for mixed types anyway.

The currently suggested resolution for shared_ptr comparison as of 1262 uses a normalization strategy: They perform the comparison on the composite pointer type (8.5.9 [expr.rel]). This is not exactly possible for unique_ptr in the presence of user-defined pointer-like types but the existing definition of std::duration comparison as of 23.17.5.6 [time.duration.comparisons] via common_type of both argument types demonstrates a solution of this problem. The approach can be seen as the general way to define a composite pointer type and this is the approach which is used for here suggested wording change.

For consistency reasons I would have preferred the same normalization strategy for == and !=, but Howard convinced me not to do so (now).

[ 2010-11-03 Daniel comments and adjustes the currently proposed wording changes: ]

Issue 1401 is remotely related. Bullet A of its proposed resolution provides an alternative solution for issue discussed here and addresses NB comment GB-99. Additionally I updated the below suggested wording in regard to the following: It is an unncessary requirement that the below defined effective composite pointer-like type CT satisfies the LessThanComparable requirements. All what is needed is, that the function object type less<CT> induces a strict weak ordering on the pointer values.

[2011-03-24 Madrid meeting]

Resolved by 1401

Proposed resolution:

Change 23.11.1.5 [unique.ptr.special]/4-7 as indicated: [The implicit requirements and remarks imposed on the last three operators are the same as for the first one due to the normative "equivalent to" usage within a Requires element, see 20.4.1.4 [structure.specifications]/4. The effects of this change are that all real pointers wrapped in a unique_ptr will order like shared_ptr does.]

template <class T1, class D1, class T2, class D2>
  bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);

? Requires: Let CT be common_type<unique_ptr<T1, D1>::pointer, unique_ptr<T2, D2>::pointer>::type. Then the specialization less<CT> shall be a function object type ([function.objects]) that induces a strict weak ordering ([alg.sorting]) on the pointer values.

4 Returns: less<CT>()(x.get(), y.get())x.get() < y.get().

? Remarks: If unique_ptr<T1, D1>::pointer is not implicitly convertible to CT or unique_ptr<T2, D2>::pointer is not implicitly convertible to CT, the program is ill-formed.

template <class T1, class D1, class T2, class D2>
  bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);

5 Effects: Equivalent to return !(y < x) Returns: x.get() <= y.get().

template <class T1, class D1, class T2, class D2>
  bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);

6 Effects: Equivalent to return (y < x) Returns: x.get() > y.get().

template <class T1, class D1, class T2, class D2>
  bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);

7 Effects: Equivalent to return !(x < y) Returns: x.get() >= y.get().