4

I have a class with a pointer member, something like:

class MyClass
{
    public:
    void setPointer(Pointer* ptr){_pointer = ptr;}

    private:
    Pointer* _pointer{nullptr};
};

MyClass doesn't own the memory to _pointer. It just has a pointer to invoke methods it requires.

I started to write ~MyClass() and I fortunately I realised it shouldn't delete _pointer because it doesn't own it.

What is the best way to show MyClass doesn't have ownership of that pointer?

EDIT:

Should I use a unique_ptr in the owner class and a shared_ptr in MyClass, or should they both use shared_ptr?

user997112
  • 29,025
  • 43
  • 182
  • 361
  • Use smart pointers should resolve your concerns without deleting pointers otherwise use a manual way to assure the ownership, so only if you are creating it in that object rather than injecting it. – muaz Jun 25 '19 at 15:12
  • @muaz Should I use smart pointers in both classes, or should I use a unique_ptr in the owner class and a shared_ptr in MyClass? – user997112 Jun 25 '19 at 16:10
  • No you can use `unique_ptr` in the owner class and pass its pointed object by using `get()` method to other classes, thus iff the `unique_ptr` destroyed -in this case when the owner is destroyed- the pointed object will be destroyed. – muaz Jun 25 '19 at 17:03

4 Answers4

14

Future

At the moment, std::observer_ptr is in discussion to express exactly those semantics: non-owning, passive pointers. See also this thread for its purpose.


Present

In idiomatic C++ (latest since 2011), it's quite uncommon to still have raw pointers that own the object they're pointing to. The reason is that new/delete come with a lot of pitfalls, while there are better alternatives such as std::unique_ptr and std::shared_ptr. Those do not only bring the semantics needed, but also express the intent in code (unique or shared ownership, respectively).

Eventually it depends on code style of your environment, but I would say until a standard best-practice is established, T* is a good convention for non-owning, passive pointers.

Community
  • 1
  • 1
TheOperator
  • 5,936
  • 29
  • 42
  • 3
    I agree with TheOperator, and I use raw pointers as non-owning and one of the modern C++ `std::unique_ptr` or `std::shared_ptr` to indicate ownership. But it is a matter of style and convention. If your programming is a mix of owning and non-owning raw pointers, then I'd add a comment to indicate if it is an owned or non-owned to clarify. The poor maintenance programmer will thank you (which may be your future self). – Eljay Jun 25 '19 at 14:52
  • 1
    It's also trivial to write `// non-owning` above the member pointer's declaration. – Lightness Races in Orbit Jun 25 '19 at 15:55
  • @LightnessRacesinOrbit already done that, but doesn't feel right. – user997112 Jun 25 '19 at 16:06
  • 1
    @user997112 Why not? – Lightness Races in Orbit Jun 25 '19 at 16:09
3

The Coreguidelines come with a support library that was a owner to mark raw pointers as owning. In that context they write:

The "raw-pointer" notation (e.g. int*) is assumed to have its most common meaning; that is, a pointer points to an object, but does not own it. Owners should be converted to resource handles (e.g., unique_ptr or vector) or marked owner.

owner<T*> // a T* that owns the object pointed/referred to; may be nullptr.

owner is used to mark owning pointers in code that cannot be upgraded to use proper resource handles.

I read that as: A raw pointer does not need to be marked as not-owning, because nowadays raw owning pointers should be the exception. Hence, it is owning raw pointers that need to be highlighted.

Of course this only applies when you consistently avoid owning raw pointers in your code.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
2

With a comment.

// A class wrapping (but not owning) a pointer.
class MyClass
{
public:
    void setPointer(Pointer* ptr){_pointer = ptr;}

private:

    // Not owned by the class
    Pointer* _pointer{nullptr};
};

Seriously, don't be afraid to document your code with comments. That's what they're there for.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

What is the best way to show MyClass doesn't have ownership of that pointer?

The lack of ownership of a resource (such as pointer to dynamic object) which you store is shown by not deallocating (deleting) the resource. Conventionally, you should never store bare identifiers (such as bare pointers) to owned resources except in a RAII wrapper (such as a smart pointer) whose sole purpose is to own and deallocate the resource.

Not taking ownership of a pointer passed to you is shown by accepting a bare resource identifier - as opposed to a RAII wrapper. This convention cannot be followed when providing a C compatible interface nor in the constructor / assignment of such RAII wrapper, which does take ownership of a bare pointer. In such non-conventional cases, the exception must be documented carefully.

The client is shown that ownership is not transferred to them by returning a bare resource identifier. This has similar exceptions with C interface as well as in the interface of the RAII wrapper, if it supports releasing ownership.

All of these can be clarified with extra documentation.


Should I use a unique_ptr in the owner class and a shared_ptr in MyClass,

No. Unique pointer means that it is the only owner of the resource. The ownership cannot be shared with other pointers. If you use a unique pointer, then you can use a bare non-owning pointer in MyClass.

or should they both use shared_ptr?

That is an option. It safer than the unique + bare pointer, because there is no need to guarantee that the lifetime of the unique pointer is longer than the lifetime of the bare pointer. The downside is some runtime overhead.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • I am aware of what I have not done properly, hence my question..... I am asking what I should do to fix this? – user997112 Jun 25 '19 at 15:48
  • @user997112 I've told you how to show the lack of ownership. If this is not what you've done, then you should do what I've described. If this is what you've done, then you're all set. I've now changed the answer to passive to avoid misunderstanding. – eerorika Jun 25 '19 at 15:53