16

I have a std::unique_ptr and another raw pointer. I want the raw pointer to point to the content of the unique_ptr without any kind of ownership. It is read-only relationship:

auto bar=std::make_unique<foo>();
auto ptr=bar.get();// This may point to another value later

Is this bad? Is there any alternative?

Note: the real example is more complex. They are not in the same class.

Humam Helfawi
  • 19,566
  • 15
  • 85
  • 160
  • 2
    Shouldn't that be `bar.get();`? – πάντα ῥεῖ Aug 11 '16 at 16:41
  • @πάνταῥεῖ yes sorry – Humam Helfawi Aug 11 '16 at 16:42
  • 3
    I'd say this is ideal. But I would probably choose a different name as there is already a `std::weak_ptr` with different semantics. – Galik Aug 11 '16 at 17:33
  • 1
    Any reason to go with a pointer and not a reference? – Daniel Jour Aug 12 '16 at 06:20
  • 1
    @DanielJour It may point to another thing later. References can not be re pointed – Humam Helfawi Aug 12 '16 at 06:21
  • One compromise (though probably a little overkill) would be to make a class that just contains a reference and overloads `operator->` and `operator*`. A solution that is much more overkill and also involves some overhead would be to use `shared_ptr` in conjunction with `weak_ptr`, which would arguably be more robust in the face of lifetime-management issues. (These alternative designs aren't necessarily better than yours; I'm just mentioning them as possibilities in case you haven't already thought of them.) – Kyle Strand Aug 16 '16 at 22:08

2 Answers2

27

No, it's not bad, and until the standard library incorporates the proposed std::observer_ptr, it's the idiomatic way of expressing a non-owning observer.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • 3
    And even after that, it will be the idiomatic way of representing that. The Core C++ guidelines don't say to use `observer_ptr`; they say that all naked `T*`s represent non-ownership. – Nicol Bolas Aug 11 '16 at 16:48
  • 5
    @NicolBolas It's a question whether they will still say that after `std::experimental::observer_ptr` becomes `std::observer_ptr`. I can imagine the guideline turning into "read `T*` as non-ownership, but write non-ownership as `std::observer_ptr`." – Angew is no longer proud of SO Aug 11 '16 at 16:54
  • 2
    "*It's a question whether they will still say that after `std::experimental::observer_ptr` becomes `std::observer_ptr`.*" And it's a question whether that will ever actually happen; TS's change between being proposed and being adopted into the core standard. Also, that will not magically transform the *billions* of lines of existing C++ code that use naked pointers for unowning pointers. – Nicol Bolas Aug 11 '16 at 16:59
  • 1
    @NicolBolas: just like `shared_ptr` and `unique_ptr` didn't transform the billions (well, it was a while ago, maybe just hundreds of millions) of lines of C++ code that used naked pointers for ownership. Naturally when reading code you have to take into account how old it is, or how old the project is whose standards it assumes. – Steve Jessop Aug 11 '16 at 20:05
  • 1
    @SteveJessop: The difference is this: using smart pointers gives you genuine improvements in the *correctness* of your code. It makes using pointers more exception safe and so forth. Using `observer_ptr` is purely *notational*; it cannot make your code more correct. Also, you have far more observing pointers in your code than you do owning naked pointers. That's why GCL's `owner` is a much better alternative; it may be notation, but you put it only on the pointers that are known to be problematic. – Nicol Bolas Aug 11 '16 at 20:40
  • @NicolBolas: well, I guess this is something to take up with Stroustrup and Sutter in the event that `observer_ptr` makes it, and they do start to advise "stop storing naked pointers at all". As Angew says, we're safe for now. – Steve Jessop Aug 11 '16 at 20:42
26

If you can guarantee that A) bar's lifetime will exceed the lifetime of ptr, AND B) that no programmer/refactoring will ever write delete ptr; at any point, then this is perfectly fine and is probably ideal for any situation where you need to pass pointers without ownership.

If those two conditions cannot be guaranteed, you should probably be using std::shared_ptr and std::weak_ptr.

Xirema
  • 19,889
  • 4
  • 32
  • 68
  • 9
    And you should probably not be using `shared_ptr`, because 99% of "wait, I can solve my resource problems with `shared_ptr`" end up being a bad idea. – Yakk - Adam Nevraumont Aug 11 '16 at 21:20
  • 5
    @Yakk At best, I would call that hyperbolic, and at worst, naive. I've encountered many problems in c++ land where the best, most idiomatic solution invoked the use of `std::shared_ptr`. I'll grant you that reliance on pointers in the first place tends to represent a cause (or symptom) of design complexity, but if they were bad '99% of the time', Java (which basically uses `shared_ptr`-like objects for all its pointers) would be unusable as a language, and we know that isn't the case. – Xirema Aug 11 '16 at 21:24
  • 5
    Do we really know that? But seriously, Java uses full gc pointers, which are a different beast than rc pointers. Thinking of rc pointers as some kind of real gc pointer is a sign of a fundamental error in design of a component, and such errors is part of that 99%. I have found situations where shared pointers are right (when you have actual *shared ownership* of some resource, not just "I don't want to think about danging pointer problems here"), but rarely can a generic owned-observed lifetime problem be solved by merely shoveling shared and weak pointers into the system. – Yakk - Adam Nevraumont Aug 11 '16 at 21:27
  • @Yakk That was the [implied] point of my conditionals: if you aren't satisfying those conditions, you're probably not working with a system which would be correctly designed as a "observer-observed" paradigm. – Xirema Aug 11 '16 at 21:31