15

For example:

std::weak_ptr<int> wp1(std::make_shared<int>());
std::weak_ptr<int> wp2;

assert(PointsToValidOrExpiredObject(wp1));
assert(!PointsToValidOrExpiredObject(wp2));

Is such a function possible?

Use case: A class's constructor takes std::weak_ptr<Foo> as a dependency. Passing an expired object is ok (might happen in certain workflows), but passing null means the programmer forget something. I'd like to test for this as part of the constructor's parameter validation.

dlf
  • 9,045
  • 4
  • 32
  • 58
  • Did you take a look at the [`expired()`](http://en.cppreference.com/w/cpp/memory/weak_ptr/expired) method? – Borgleader Nov 13 '14 at 16:34
  • @Borgleader. Yes--unfortunately, it returns true for both cases. – dlf Nov 13 '14 at 16:34
  • 1
    While there does seem to be an answer, a less magical solution might be to wrap the weak pointer in a type that can only be constructed with a non-empty shared pointer, and require that rather than a raw weak pointer. – Mike Seymour Nov 13 '14 at 17:28

1 Answers1

17

std::weak_ptr::owner_before can distinguish between weak pointers that are empty and expired. You can therefore implement PointsToValidOrExpiredObject as:

template <typename T>
bool PointsToValidOrExpiredObject(const std::weak_ptr<T>& w) {
    return w.owner_before(std::weak_ptr<T>{}) ||
           std::weak_ptr<T>{}.owner_before(w);
}

Demo.

Regarding the original uncertainty I had about an expired weak_ptr still maintaining ownership: I'm now certain that the general library-wide thread-safety requirements mandate that an expired weak_ptr continues to have the same ownership. Otherwise, destroying the last remaining shared_ptr in thread A would have to observably modify the state of one/some/all weak_ptrs that share ownership with the shared_ptr in question. If thread B was simultaneously examining the state of such a weak_ptr then you would have a data race introduced by the library implementation which is forbidden in general.

Community
  • 1
  • 1
Casey
  • 41,449
  • 7
  • 95
  • 125
  • That does indeed seem to be the case. The pointers are equivalent "if they share ownership or are both empty", and there's nothing to indicate that a weak pointer becomes empty (and stops sharing ownership) when it expires. – Mike Seymour Nov 13 '14 at 17:23
  • 1
    Great! I had to look up the `owner_before` documentation to understand what this means and why it works. For others in the same situation: you can think of this function like an `operator <` that, in practice, compares addresses. So if this < null OR null < this, you can conclude that this != null (and this holds even if the implementation is not actually based on addresses). It sounds like the main reason `owner_before` exists is to facilitate the use of `weak_ptr` as the key in a map, but it's useful here too! – dlf Nov 13 '14 at 18:17