c z
c z

Reputation: 9027

In *modern* C++ how should I manage *unowned* pointers?

In modern C++ how should I manage unowned pointers? I was thinking something like a weak_ptr for unique_ptr, but that doesn't seem to exist.

Example

For instance, if I have a class A that owns a pointer, I should use unique_ptr<X> instead of an old X* pointer, e.g.

class A
{
    std::unique_ptr<X> _myX;
};

But then if I have another class B that uses this pointer, what do I do here? With C style pointers I would do this:

class B
{
    X* _someX;
};

That seems correct, but it isn't obvious from the code that I've referenced another object's pointer (for instance a reader may think I could have just not used a smart pointer).

I have considered the following

This seems like an obvious issue and sorry if it's been asked before. I've looked around and I have seen this question, but unfortunately the OP asked "is it OK to use X*" in one specific case. I'm looking for what I should generally be doing instead of X*, (if anything!).

Upvotes: 6

Views: 2589

Answers (4)

Drew Dormann
Drew Dormann

Reputation: 63912

Bjarne Stroustrup has weighed in on this matter.

Pointers are really good at pointing to "things" and T* is a really good notation for that ... What pointers are not good at is representing ownership

He makes two suggestions:

  • Consider T* to mean "non-owning pointer to T" in modern C++
  • Use template<typename T> using observer_ptr = T*; if you desire your variable declarations to explicitly document this non-ownership.

Upvotes: 13

Alec Story
Alec Story

Reputation: 11

https://abseil.io/tips/116 is a good discussion of the options here. If you have the thing at construction time, and never need to repoint it, then T& is probably good. If you don't, then "hey this might be null" is part of reality for that pointer, and T* is fine - a "raw" pointer in modern C++ generally communicates an optional, non-owning reference.

Upvotes: 1

eerorika
eerorika

Reputation: 238411

That seems correct, but it isn't obvious from the code that I've referenced another object's pointer

Ideally, it should be obvious. If the pointer owned the resource, then it should have been a smart pointer. Since it isn't a smart pointer, that implies that it shouldn't own the resource.

That said, in the reality that has C / ancient C++ / badly designed interfaces which use owning pointers, you can clarify the lack of ownership like this:

class B
{
    X* _someX; // no ownership
};

It is also possible to define a custom class template wrapper for this purpose, and there has been a proposal to include such template in the standard library, which was adopted as a technical specification, but has not been adopted into the standard proper. To my understanding, there's no consensus on whether such wrapper is useful or unnecessary.

Upvotes: 5

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122994

Your question is largely opinion based, but we can take a look at what the core guideline has to say about it:

R.3: A raw pointer (a T*) is non-owning

Reason

There is nothing (in the C++ standard or in most code) to say otherwise and most raw pointers are non-owning. We want owning pointers identified so that we can reliably and efficiently delete the objects pointed to by owning pointers.

The guideline promotes to never use a raw pointer when it is an owning pointer. Once you do that, a raw pointer also readily signals that it is non-owning. The downside of this interpretation is:

Exception

A major class of exception is legacy code, especially code that must remain compilable as C or interface with C and C-style C++ through ABIs. The fact that there are billions of lines of code that violate this rule against owning T*s cannot be ignored. [...]

Not all raw pointers are non-owning, and often we cannot do much about that. However, if your code is written after C++11, then using a raw pointer should be sufficient to signal that it is not an owning pointer.

Upvotes: 2

Related Questions