Search code examples
c++shared-ptr

Is it possible to have a static object and a static std::shared_ptr pointing to the same object?


Given the following class:

class Foo : public Base {
public:
  static const Foo FOO;
  static const std::shared_ptr<Foo> FOO_PTR;
  // .. virtual methods, etc
};

Is it possible to make it so that FOO_PTR points to FOO?

It seems hard since the usual way of creating a shared pointer is by taking ownership of a dynamically created pointer (e.g., via new Foo{}) or via std::make_shared<Foo>() both of which create a new object and don't really allow you to point the shared_ptr to FOO. Similarly, if I create the pointer first, it will have a different identity from FOO and so I think I am screwed here too.

A really dirty hack could be something like:

Foo Foo::FOO = Foo{};
std::shared_ptr<Foo> Foo::FOO_PTR = &Foo::FOO;  // dirty hack
Foo* dummy = new shared_ptr<Foo>(FOO_PTR);      // leaky, yuck

Basically we create the static FOO object first, then initialize the shared_ptr<FOO> with a pointer to that object. Now of course this object wasn't create via new so if the shared_ptr ever tries to delete it the world will probably end. To get around that the last thing we do is create another shared_ptr from the first, incrementing its reference count, and leak it, so the original shared_ptr will never try to delete its pointer.

Naturally, this makes me feel gross and I'm looking for a better solution.

Now an obvious solution would not be expose the FOO and/or FOO_PTR static objects in the first place but my hands are tied here and I cannot change that part of the design.


Solution

  • Not sure if it helps you with the API restrictions, but you could turn it around in that you create a shared_ptr-object dynamically and let foo be of type Foo& then:

    class Foo {
    public:
        static const Foo &FOO;
        static const std::shared_ptr<Foo> FOOPTR;
    };
    
    const std::shared_ptr<Foo> Foo::FOOPTR = make_shared<Foo>();
    const Foo &Foo::FOO = *Foo::FOOPTR;
    
    int main() {
        const Foo* f1 = Foo::FOOPTR.get();
        const Foo* f2 = &Foo::FOO;
    
        printf("%p == %p \n",(void*)f1,(void*)f2);
    }