Question

I noticed that the stdlib doesn't provide an overload for the equality operator for a shared_ptr and a raw pointer. This especially unhandy if, say, you have a std::unordered_set<std::shared_ptr<Foo>> and you want to erase elements by passing a raw Foo*

Is there any specific reason that there is no such overload? As I see it, it is easy to implement:

template<typename T1, typename T2>
bool operator==(const T1 * a, const std::shared_ptr<T2> & b) {
    return a == b.get();
}

...would there by anything dangerous or unexpected with this implementation?

Was it helpful?

Solution

For an unordered_set you need more than just ==, you also need hash to work.

For set, a transparent comparator lets you look things up by things that are not the key type. set is not transparent by default, so that operator would do no good.

Once you add your own comparator, you can override == for it.

Sadly, unordered_set does not have a transparent option at this point in time. In order to find/erase/etc something in an unordered_set, you must have the key type.

Your overload is questionable. A better one is:

template<class U, class...Ts>
auto operator==( U const* lhs, std::shared_ptr<Ts...> const& rhs )->decltype( lhs == rhs.get() ) {
  return lhs == rhs.get();
}
template<class U, class...Ts>
auto operator==( std::shared_ptr<Ts...> const& lhs, U const* rhs )->decltype( lhs.get() == rhs ) {
  return lhs.get() == rhs;
}

but note that writing the above reasonably requires C++11 support. A solution short of the above ends up being either a mess to write (with SFINAE), or claiming that there is a == between types there is not (and failing too late for other SFINAE code to realize it).

But what about <? Well, < on raw pointers is only a good idea within the same object, so exposing it between shared pointers and raw pointers seems like a horrid idea. So now we are approaching std::less and wanting to augment it with transparent support between smart pointers and non-smart pointers.

Do we also support mixing smart pointers (a shared and unique?) -- naively, you might say no, but a unique_ptr does not have to represent memory ownership if you replace the deleter! (the same is true of a shared_ptr). Should smart pointers with different deleters be considered equal or equivalent? The meaning of the data may be very different based on the deleter.

Now, given that I have managed to come up with thorny questions from just a few minutes of work, and such an overload would encourage mixing of raw pointers and shared_ptr, and it doesn't even help solve the problem you wanted to solve with it, maybe it isn't a good idea.

Or maybe it is. Which leads to the real reason why it isn't in the standard.

Nobody proposed it and got it accepted.

If you think it is a good idea, I encourage you to look into the proposal process. Examine other proposals, figure out the right steps, and throw a proposal together.

If that seems too intimidating, you might want to create a robust library that provides said comparison operators, and get it into boost, and mayhap people will use it and say "wow, we always needed that!"

OTHER TIPS

If you're working with a shared_ptr, it's very dangerous to pass around raw pointers, since if you have something holding that raw pointer, it by definition breaks the shared_ptr concept of reference counts. The reason there's no overload is probably to discourage this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top