What is the usability of providing relational operators '<', '>' for unique_ptr

Hi,

I was just wondering what is the reason for providing relational operators '<', '>' for unique_ptr ?

I have never come across any code using these relational operators for unique_ptr.

Please provide a scenario where these operators could be useful.

Thanks for any help :)
What is the use of < and > for regular pointers?
> what is the reason for providing relational operators '<', '>' for unique_ptr ?

The relational operators (<, > etc.) for smart pointers are more involved than the same operators for normal object pointers. Unlike the relational operators for built-in pointers, which only impose a partial ordering, these operators for smart pointers are required to impose a total ordering.

For example, for operator<:
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 denote
common_type_t<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer>

Then the specialization less<CT> shall be
a function object type that induces a strict weak ordering on the pointer values.

#Returns: less<CT>()(x.get(), y.get()).
http://eel.is/c++draft/unique.ptr.special#5



> provide a scenario where these operators could be useful.

Howard Hinnant presented the following motivating example:
1
2
3
4
5
6
struct base {...};
struct derived : base {...};
vector<unique_ptr<base>> sorted_vec;
...
unique_ptr<derived> d(...);
vector<unique_ptr<base>>::iterator i = lower_bound(sorted_vec.begin(), sorted_vec.end(), d);

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2853.pdf
It's a bit unfortunate that the < operator defines the default sort order. It often makes sense to be able to sort objects in some consistent order, but the relational operators doesn't really make much sense for most types.
Last edited on
Thanks JLBorges and Peter87 for providing your feedback :)
I have some further clarifications :

JLBorges wrote:

vector<unique_ptr<base>> sorted_vec;
vector<unique_ptr<base>>::iterator i = lower_bound(sorted_vec.begin(), sorted_vec.end(), d); [1]


For [1] to be successful, sorted_vec must be sorted that justifies the need for providing '<' operator.
But on what basis is this sorting done ?
[a] On the basis of value that we get from .get() ; i.e. the address of object pointed by the unique_ptr
[b] On the basis of value pointed by the unique_ptr, i.e. on the basis of *(.get()) ?

[c] If it is on the basis of [a], then I wonder why would we want to sort the pointer array on the basis of the address of the objects they point to ?
The comparison is done based on the value returned by get() (the address of the managed object).
(Note that the deleter does not participate in these comparisons.)


> why would we want to sort the pointer array on the basis of the address of the objects they point to ?

I can't think of a very good use case for sorting a sequence of unique pointers.
Last edited on
Thanks for the reply JLBorges :)
My reply (the one you ignored) was probably the most useful, if you would just take the time to think about it.
JLBorges initial reply basically just said that unique_ptr's must be unique.
Mine was asking "what is the use in the built-in case"?
@dutch
dutch wrote:

What is the use of < and > for regular pointers?


I am sorry dutch but I have never used '<' or '>' for regular pointers.

Also I tried to search for examples illustrating the use of '<' for regular pointers and unique_ptr but could not get a very satisfying answer.

It would be great if you could explain a scenario where '<' could really be useful for regular pointer as well as unique_ptr.
Last edited on
> I am sorry dutch but I have never used '<' or '>' for regular pointers.

It is easy to think of some use cases for sorting sequences of shared pointers or raw pointers.

For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <vector>
#include <algorithm>
#include <memory>

struct person { /* .... */ };

int main()
{
    {
        using pointer = std::shared_ptr<person> ;
        std::vector<pointer>  people ;
        std::vector<pointer>  programmers ;
        std::vector<pointer>  musicians ;
        // etc.

        // populate

        // preprocess: sort
        std::sort( std::begin(programmers), std::end(programmers) ) ;
        std::sort( std::begin(musicians), std::end(musicians) ) ;

        // now answer queries on sets
        // eg. find all programmers who are also musicians
        std::vector<pointer>  programmer_musicians ;
        std::set_intersection( std::begin(programmers), std::end(programmers),
                               std::begin(musicians), std::end(musicians),
                               std::back_inserter(programmer_musicians) ) ;
    }

    {
        using pointer = person* ;
        std::vector<pointer>  people ;
        std::vector<pointer>  programmers ;
        std::vector<pointer>  musicians ;
        // etc.

        // populate

        // preprocess: sort note: use std::less<> to impose a total order on the pointers
        std::sort( std::begin(programmers), std::end(programmers), std::less<>{} ) ;
        std::sort( std::begin(musicians), std::end(musicians), std::less<>{} ) ;

        // now answer queries on sets
        // eg. find all programmers who are also musicians
        std::vector<pointer>  programmer_musicians ;
        std::set_intersection( std::begin(programmers), std::end(programmers),
                               std::begin(musicians), std::end(musicians),
                               std::back_inserter(programmer_musicians) ) ;
    }
}
One more reason which I could find is that we need these operators to be provided so that unique_ptr's can be stored in ordered containers.

Thanks for all your responses :)
One more reason which I could find is that we need these operators to be provided so that unique_ptr's can be stored in ordered containers.

You mean like std::set and std::map? Is that ever actually useful?
Last edited on
Peter87 wrote:

You mean like std::set and std::map?


Yes.
umm... I also cant think of any use-case why would storing them in an ordered container make sense. Maybe to ensure that containers can store unique_ptr's as well ?
Topic archived. No new replies allowed.