Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return a smart pointer to a member variable?

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.

like image 629
Logical Fallacy Avatar asked Apr 07 '15 18:04

Logical Fallacy


People also ask

Can you return a smart pointer?

Return smart pointers from functions You should follow the same logic above: return smart pointers if the caller wants to manipulate the smart pointer itself, return raw pointers/references if the caller just needs a handle to the underlying object.

Can I return a shared pointer?

So the best way to return a shared_ptr is to simply return by value: shared_ptr<T> Foo() { return shared_ptr<T>(/* acquire something */); }; This is a dead-obvious RVO opportunity for modern C++ compilers.

Which method is used to return a shared pointer that you can get the value from when using a weak pointer?

There is an implicit conversion from shared_ptr to weak_ptr ; returning a shared_ptr from a function whose return type is weak_ptr will just call the conversion.

Do smart pointers delete themselves?

To make use of smart pointers in a program, you will need to include the <memory> header file. Smart pointers perform automatic memory management by tracking references to the underlying object and then automatically deleting that object when the last smart pointer that refers to that object goes away.


2 Answers

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).

like image 143
Angew is no longer proud of SO Avatar answered Sep 21 '22 04:09

Angew is no longer proud of SO


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.

like image 34
Barry Avatar answered Sep 23 '22 04:09

Barry