Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::shared_ptr - Best practice for passing shared pointer as parameter

Tags:

c++

c++11

I've been away from serious C++ for about ten years. I'm coming back in to the fold and am currently working on a project to fully familiarize myself with C++11. I'm having a bit of an existential crisis about how to best pass std::shared_ptr's around.

For a simple example, take the following setup:

class ServiceB {
public:
    ServiceB() {}
};

class ServiceA {
public:
    ServiceA(std::shared_ptr<ServiceB>& serviceB)
        : _serviceB(serviceB) {

    }

private:
    std::shared_ptr<ServiceB> _serviceB;
};

class Root {
public:
    Root()
        : _serviceB(std::shared_ptr<ServiceB>(new ServiceB())),
        _serviceA(std::unique_ptr<ServiceA>(new ServiceA(_serviceB))) {

    }

private:
    std::shared_ptr<ServiceB> _serviceB;
    std::unique_ptr<ServiceA> _serviceA;
};

Notice here that ServiceA requires a reference to ServiceB. I'd like to keep that reference tied up in a shared_ptr. Am I okay to do what I did here, which is simply pass the shared_ptr down as a reference and let the std::shared_ptr copy constructor do the work for me? Does this properly increment the reference count on the shared_ptr?

If this is not the best way to do this, what is the common "best practice" for passing around std::shared_ptr's?

like image 902
Matt Holmes Avatar asked Jan 03 '14 17:01

Matt Holmes


People also ask

Should you pass shared pointers by reference?

In general, you should pass the shared pointer as a straight copy. This gives it its intended semantics: Every scope that contains a copy of the shared pointer keeps the object alive by virtue of its "share" in the ownership.

Can you pass a std :: unique_ptr as a parameter to a function?

A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr , passed by value to a function, or used in any C++ Standard Library algorithm that requires copies to be made. A unique_ptr can only be moved.

Why is shared_ptr unique deprecated?

Indeed, once unique, a managed resource can't become shared by an action originating from another thread. The same pattern would be possible with shared_ptr if enable_shared_from_this did not exist. This is why IMHO, unique() has been removed from C++20: misleading.


2 Answers

You should pass around shared pointers exactly as you pass around other objects. If you need to store a copy (of the shared pointer, not the pointed at object), pass by value, and move to its destination.

ServiceA(std::shared_ptr<ServiceB> serviceB)
    : _serviceB(std::move(serviceB)) {}

Alternatively, if you don't mind writing two constructors, you can save a tiny bit of performance (one call to the shared pointer's the move constructor) by writing one which takes a const reference and copies it, and one which takes an r-value reference, and moves it.

ServiceA(std::shared_ptr<ServiceB> const& serviceB)
    : _serviceB(serviceB) {}

ServiceA(std::shared_ptr<ServiceB> && serviceB)
    : _serviceB(std::move(serviceB) {}
like image 169
Benjamin Lindley Avatar answered Nov 05 '22 14:11

Benjamin Lindley


Either pass by value (compilers are pretty good at eliding copies) or by const reference - non-const reference as you have makes it look like you intend to modify the parameter.

Also for new code consider using unique_ptr for parameters and return values where it makes sense, or where the sharing isn't part of the contract. (You can make a shared_ptr from a unique_ptr, but not vice versa.)

like image 2
Alan Stokes Avatar answered Nov 05 '22 16:11

Alan Stokes