Search code examples
c++shared-ptrsmart-pointers

Is it OK to save a reference to the object managed by a shared_ptr?


Here's a working version of what I'm doing.

#include <memory>

using namespace std;

struct thing {
    int blah;
};

struct parentObj {
    parentObj(thing & incomingThing) : isThisOK(incomingThing) {};
    thing & isThisOK;
};

int main()
{
    shared_ptr<thing> thingInstance = make_shared<thing>();
    shared_ptr<parentObj> theObj = make_shared<parentObj>(*thingInstance);
}

I like assigning a shared pointer to a reference of it's type. (ctrl+f isThisOK)

Are there unintended consequences here? Should I be using a weak pointer?


Solution

  • It is just as okay as this:

    #include <memory>
    
    using namespace std;
    
    struct thing {
        int blah;
    };
    
    struct parentObj {
        parentObj(thing& incomingThing) : isThisOK(incomingThing) {};
        thing& isThisOK;
    };
    
    int main()
    {
        thing thingInstance;
        shared_ptr<parentObj> theObj = make_shared<parentObj>(thingInstance);
    }
    

    Just like function parameter should, by default, be agnostic of the ownership strategy unless needed, I would say that what you're doing is right, and even recommend it given a particular case. If your object is agnostic of the ownership strategy unless needed, this is usually the way to go.

    Just be aware of two things:

    1. You'll have to be careful with your lifetime and set a boundary when a parentObj should be considered invalid.
    2. Be aware that this is much easier to do something like your code when you use std::unique_ptr instead, since the owner of a unique pointer is much easier to track. When reading a code with unique pointers, you can easily spot where the lifetime should end and where it is transferred. With a shared one, not so clear. With a unique pointer, you can set the boundary "statically", let's say, a parentObj is invalid after the thing died, and it should be clear when the lifetime of both has ended. If you have a shared pointer, I would recommend you have a way to check the validity at runtime before using the parentObj.

    I would use a std::weak_ptr only if by design parentObj should check the validity of thing at runtime, and users of parentObj cannot check the validity of thing. Usually, there is a place in the code that you can be sure when thing and parentObj start and end their lifetime. If you have a place where you know their lifetime, then I would say that it's the responsibility of that code to check the validity of thing and parentObj and let those two type be simpler.