4

I have an object, Window, who has a member std::unique_ptr<Texture>. I use a unique pointer, because Window really owns the texture, and it doesn't make sense to use said Texture after Window has been destroyed.

Window has a method, Texture& Window::getTexture(). The idea being that sometimes code external to Window will say myWindow.getTexture(), do something with the texture, and then be done with it.

The risk is that someone holds onto the Texture reference which becomes invalid after Window's destruction. I could instead have window hold an std::shared_ptr<Texture> and std::weak_ptr<Texture> Window::getTexture() but shared_ptr feels wrong to me when Window is the sole owner of the texture, and the texture is never meant to outlive the Window.

Is there a particular pattern I should use in a case like this, or is a reference the way to go? In the old days I would of course just return a pointer.

EDIT: I may be overthinking this, here is an example of a normal usage

Texture& tex = myWindow.getTexture();
context.drawHere(tex);
context.drawThere(tex);
context.drawEverywhere(tex);

The calling code would have to do something very abnormal to hold onto the reference, normally you just use it for a few draw calls (which don't hold onto anything). Is this a non-issue, or is there a pattern of some sort I should use to make this explicit beyond documentation?

CrazyNorman
  • 185
  • 1
  • 9
  • 1
    Whatever calls getTexture should own Texture, then it can't be an issue – paulm Mar 14 '15 at 13:29
  • 1
    Perhaps return a plain old pointer, and document that it will bet invalidated when the `Window` goes out of scope? – juanchopanza Mar 14 '15 at 13:29
  • @juanchopanza: But does this avoid the risk mentioned by the OP? I.e. someone keeps the raw pointer after the `Window` was destroyed. Of course, they'd have to ignore the documentation for that. But they would do that in the case of the reference as well, because a reference is kind of self-documenting regarding this specific ownership issue, isn't it? – Christian Hackl Mar 14 '15 at 13:33
  • How about `Window::updateTexture(std::unique_ptr ptr)` and then `reset` it? – edmz Mar 14 '15 at 13:37
  • I think this question cannot be really answered as long as we don't know who will call `getTexture` and for what purpose. – Christian Hackl Mar 14 '15 at 13:38
  • @ChristianHackl I've updated my description with a standard example of getTexture() usage. – CrazyNorman Mar 14 '15 at 13:52
  • @CrazyNorman: OK. Personally, I don't think you need anything more complex than a reference here. You will never be able to completely keep clients from doing dangerous things. After all, even if you returned a `std::shared_ptr`, nothing would stop them from `delete p.get()`. – Christian Hackl Mar 14 '15 at 13:59

2 Answers2

4

I like the approach promoted by Herb Sutter and others to put raw refs or pointers in the interface and use smart pointers for ownership management. You just need to make sure that the users of your interfaces understand the rules.

sfjac
  • 7,119
  • 5
  • 45
  • 69
1

Perhaps, you should not expose Texture outside your class and create specific methods in Window in order to do specific action on his texture. If you cannot do that, then you need to use a shared ptr, it is safer and does not impact performance so much.

Hope it helps.