0

As far I understood, the proposed std::observer_ptr is related to std::unique_ptr in the same way as std::weak_ptr is related to std::shared_ptr.

So why does the std::observer_ptr<W> interface, according to the proposal N4282, allow the construction from a W* pointer?

This implies an implementation which contains a W* as member, maybe similar to the pseudo-implementations given in this answer, which most simply proposes

template<typename T>
using observer_ptr = T*;

As a consequence, this seems to outrule validity checks as in the following:

std::unique_ptr<W> u = std::make_unique<W>();
std::observer_ptr<W> o(uptr.get());
uptr.reset();

if(o)
{
     //u is already nullptr, but o doesn't know
     o->foo();  //invalid dereferentation
}

Instead I would expect to only be allowed to do the following:

std::unique_ptr<W> u = std::make_unique<W>();
std::observer_ptr<W> o(uptr);
uptr.reset();

if(o)
{
     //execution doesn't get here, o is nullptr
}

This is equivalent to what one can do with std::weak_ptr by locking it, and is imo the central advantage observer_ptr could offer over a non-owning raw pointer.

So, again, why isn't it enforced?

Community
  • 1
  • 1
davidhigh
  • 14,652
  • 2
  • 44
  • 75
  • Where did you get the idea that you can check whether such a pointer is valid? – molbdnilo Jan 21 '16 at 11:09
  • @molbdnilo: as written, from the `std::weak_ptr` parallel. That would be only natural imo, see also [this answer](http://stackoverflow.com/a/17561445/2412846) that seems to make the same assumption. – davidhigh Jan 21 '16 at 11:50
  • That answer's "would hold no responsibility [...] for correctly responding to the deletion of that object" says the opposite. – molbdnilo Jan 21 '16 at 11:54
  • @molbdnilo: you're right, I was distracted by the question title ["*shared_ptr<> is to weak_ptr<> as unique_ptr<> is to… what?*"](http://stackoverflow.com/questions/17536731/shared-ptr-is-to-weak-ptr-as-unique-ptr-is-to-what). I'm still not getting why there is no "*... what*" in the standard. My intuitive candidate for it was `observer_ptr`. – davidhigh Jan 21 '16 at 12:02
  • 2
    What would you have it do? Store a `unique_ptr*`? That's pretty useless. – T.C. Jan 21 '16 at 12:27
  • @T.C.: I agree, but it's more useful than the current `observer_ptr`. I mentioned one possible use case in the question -- validity checking (maybe that's the only, but in any case it adds to what `observer_ptr` gives). – davidhigh Jan 21 '16 at 12:28
  • Not really. You can't detect when the `unique_ptr` has been destroyed - which is probably the most common case where the underlying pointer becomes invalid. And you treat move-from, `release()`, and `reset()` all in the same way. – T.C. Jan 21 '16 at 12:33
  • @T.C.: I don't understand your comment. When you have a `unique_ptr* p`, and you `reset()`, `release()` or move the pointed-to `unique_ptr`, `*p` becomes `nullptr`. That's good, as you can check the validity of `*p`. When you have a raw pointer `q` pointing to the member pointer of a `unique_ptr` -- as `observer_ptr` does -- and then call `reset()` etc. on the `unique_ptr`, `q` becomes invalid. And there is no direct way to check its validity. That's bad. This is why I would think `unique_ptr*` is more useful than a raw pointer. – davidhigh Jan 21 '16 at 12:45
  • 1
    Let's say `observer_ptr` stores a `unique_ptr*`. `std::observer_ptr o; { std::unique_ptr u = std::make_unique(); o = uptr; }`. How do you check that the validity of `o` after this? you can't. Meanwhile, you also made `observer_ptr` unusable with stack objects. And this is also a simplification because `unique_ptr` is templated on the deleter, so your `observer_ptr` must either be so templated or erase the type. – T.C. Jan 21 '16 at 12:52
  • @T.C.: Thanks. I take away that there is no foolproof way of validity checking -- at least without changing `unique_ptr` -- and that's the reason why it isn't in the standard. – davidhigh Jan 21 '16 at 13:08

1 Answers1

9

As far I understood the proposed std::observer_ptr is related to std::unique_ptr in the same way as std::weak_ptr is related to std::shared_ptr.

That is a misconception. It has no relation to unique_ptr. It expresses that there is no connection to the ownership of the pointee.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • Thanks for your answer, So, where then is the `std::weak_ptr` parallel for `std::unique_ptr`? – davidhigh Jan 21 '16 at 11:47
  • 1
    @davidhigh - There isn't any. As `unique_ptr` should either own the pointer or contain a nullptr, there isn't much to check. – Bo Persson Jan 21 '16 at 12:02
  • 1
    @Bo Persson: ok, thanks, I got it. But it's inconsistent to `weak_ptr`. And also useless: C++ protects against Murphy, not Machiavelli. There's no advantage in a class which hides `delete`. However, there is (at least a small) one in a class which parallels `weak_ptr`, see my question. – davidhigh Jan 21 '16 at 12:11
  • 4
    @davidhigh The point isn't to hide `delete`, it's to mark the fact that you have a pointer and you're just going to use it to observe the pointee, not sacrifice it at the holy altar of the free store once it is no longer of use to you. – TartanLlama Jan 21 '16 at 12:15
  • @TartanLlama: I understand. But someone has to own the initial instance. `weak_ptr` knows who this someone is. `observer_ptr` doesn't (which might be semantically useful for some people). But there has to be a third concept which expresses "there is a single owner and I know it". It is lacking the smart-pointer conception. – davidhigh Jan 21 '16 at 12:27