user3666471
user3666471

Reputation: 945

Storing pointer of singleton in class

I'm debugging some code and I ran across this snippet that was crashing, the problem is that the singleton pointer and the local pointer are not the same address. I'm not sure why that is.

The code roughly looks like this:

class B;

class I_A : public std::enable_shared_from_this<I_A> {
    public:
    virtual std::shared_ptr<B> make() = 0;
};

class A : public I_A {
  public:
    std::shared_ptr<B> make() override {
        return std::make_shared<B>(shared_from_this());   
    }
};

static std::shared_ptr<I_A> getInstance() {
    static std::shared_ptr<I_A> ptr;
    if(!ptr) {
        std::cout << "Making new instance\n";
        ptr = std::make_shared<A>();   
    }
    std::cout << "Ptr is " << ptr << '\n';
    return ptr;
}

class B {
    public:
    B(const std::shared_ptr<I_A>& ptr) : ptr(ptr) {
        std::cout << "In B() " << ptr << '\n';
    }

    void foo() {
        std::cout << "B::ptr " << ptr << '\n';
        assert(ptr == getInstance());   
    }

    private:
        const std::shared_ptr<I_A>& ptr; // Potential problem here
};


int main() {
    auto bPtr = getInstance()->make();
    bPtr->foo();
}

But if I store a copy of shared_ptr<I_A> in B instead of storing a ref, everything works fine.

If my understanding is correct, the singleton should never change the address, but the B::ptr and getInstance() have different addresses.

Any idea why that is?

Upvotes: 4

Views: 554

Answers (1)

Caleth
Caleth

Reputation: 63117

You should (approximately) never use const std::shared_ptr<T>&, for any T. Just use a std::shared_ptr<T>. Would you use a T * const &?

The problem you are observing is that the instance of std::shared_ptr<I_A> that you get from A::shared_from_this() is a temporary, and it has ceased to exist by the time you can use your B. You then use a dangling reference, which has undefined behaviour.

Upvotes: 6

Related Questions