20

I'm attempting to create an accessor for a class member variable using smart pointers. Here's the code:

class MyResource
{
};

class MyClass
{
public:
    std::unique_ptr<MyResource> getResource();
private:
    std::unique_ptr<MyResource> resource;
};

std::unique_ptr<MyResource> MyClass::getResource()
{
    return this->resource;
}

The error I get trying to compile this:

cannot access private member declared in class 'std::unique_ptr<_Ty>'

Adding .get to this->resource of course doesn't work because the return type changes.

Should I not be using a unique_ptr here? Is this just a syntax issue? Am I totally on the wrong track?

my background with smart pointers: I've been using plain-old-pointers for a couple of years now in part because I can't find a solid explanation of when to use which types of smart pointers and how to go about using them. I'm tired of making excuses, so I'm just diving in. I think I understand what smart pointers are and why to use them, but I understand very little of the details. At the moment I'm totally lost in the endless Q&A about smart pointers.

Barry
  • 247,587
  • 26
  • 487
  • 819
Logical Fallacy
  • 2,619
  • 4
  • 22
  • 37

2 Answers2

30

The most important thing to understand about smart pointers is that the "pointer" aspect is not the fundamental part of their semantics. Smart pointers exist to represent ownership. Ownership is defined as the responsibility for cleanup.

A unique pointer says: "I am the sole owner of the pointee. I will destroy it when I go out of scope."

A shared pointer says: "I am one of a group of friends who share the responsibility for the pointee. The last of us to go out of scope will destroy it."

(In a modern C++ program,) A raw pointer or reference says: "I do not own the pointee, I merely observe it. Someone else is responsible for destroying it."

In your case, using a unique_ptr for the member type means that MyClass owns the MyResource object. If the getter is supposed to transfer ownership (that is, if the MyClass is giving up the resource to whoever called the getter), returning a unique_ptr is appropriate (and you'll have to return std::move(resource); to make the ownership transfer explicit).

If the getter is not supposed to give up the ownership (which I consider the likely scenario), just return a plain old pointer (if returning a null pointer is an option) or a plain old reference (if returning null is not an option).

Angew is no longer proud of SO
  • 156,801
  • 13
  • 318
  • 412
21

You have several options here, depending on the semantics you wish your class to observe.

  1. You want to give up ownership of your resource:

    std::unique_ptr<MyResource> MyClass::releaseResource() {
        return std::move(this->resource);
    }
    
  2. You want to maintain unique ownership, but have somebody else use it:

    MyResource& MyClass::getResource() {
        assert(this->resource);
        return *(this->resource);
    }
    
  3. You want to share ownership, so the resource doesn't get destroyed if MyClass goes out of scope: switch everything to std::shared_ptr<MyResource> and still return by value.

πάντα ῥεῖ
  • 83,259
  • 13
  • 96
  • 175
Barry
  • 247,587
  • 26
  • 487
  • 819