Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++0x Smart Pointer Comparisons: Inconsistent, what's the rationale?

In C++0x (n3126), smart pointers can be compared, both relationally and for equality. However, the way this is done seems inconsistent to me.

For example, shared_ptr defines operator< be equivalent to:

template <typename T, typename U>
bool operator<(const shared_ptr<T>& a, const shared_ptr<T>& b)
{
    return std::less<void*>()(a.get(), b.get());
}

Using std::less provides total ordering with respect to pointer values, unlike a vanilla relational pointer comparison, which is unspecified.

However, unique_ptr defines the same operator as:

template <typename T1, typename D1, typename T2, typename D2>
bool operator<(const unique_ptr<T1, D1>& a, const unique_ptr<T2, D2>& b)
{
    return a.get() < b.get();
}

It also defined the other relational operators in similar fashion.


Why the change in method and "completeness"? That is, why does shared_ptr use std::less while unique_ptr uses the built-in operator<? And why doesn't shared_ptr also provide the other relational operators, like unique_ptr?

I can understand the rationale behind either choice:

  • with respect to method: it represents a pointer so just use the built-in pointer operators, versus it needs to be usable within an associative container so provide total ordering (like a vanilla pointer would get with the default std::less predicate template argument)
  • with respect to completeness: it represents a pointer so provide all the same comparisons as a pointer, versus it is a class type and only needs to be less-than comparable to be used in an associative container, so only provide that requirement

But I don't see why the choice changes depending on the smart pointer type. What am I missing?


Bonus/related: std::shared_ptr seems to have followed from boost::shared_ptr, and the latter omits the other relational operators "by design" (and so std::shared_ptr does too). Why is this?

like image 473
GManNickG Avatar asked Oct 14 '10 02:10

GManNickG


1 Answers

This was a defect in drafts of C++11; a defect report was opened to change the std::unique_ptr relational operator overloads to use std::less: see LWG Defect 1297.

This was fixed in time for the final C++11 specification. C++11 §20.7.1.4[unique.ptr.special]/5 specifies that the operator< overload:

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

where x and y are the two operands of the operator and CT is the common type of the two pointers (since pointers to different types, e.g. with different cv-qualifications, can be compared).

like image 184
James McNellis Avatar answered Oct 10 '22 17:10

James McNellis