-1

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.

BeeOnRope
  • 60,350
  • 16
  • 207
  • 386
  • 2
    Why would you want the shared pointer to point to an object that wasn't dynamically allocated? – juanchopanza Nov 28 '17 at 22:53
  • 1
    You would not use `shared_ptr` since the whole point is managing heap memory, which you don't have here. You want `static const Foo* FOO_PTR;` – zzxyz Nov 28 '17 at 22:55
  • @juanchopanza - because the use of `shared_ptr` to hold objects of type Foo (and in particular many other types like Foo which share a common base class and `virtual` functions) is embedded in the API. Most of these objects are actually created and destroyed dynamically and the `shared_ptr` use is conventional, but there are also some singleton objects like `FOO` and `FOO_PTR` which are only created once but must place nice with the existing `shared_ptr` APIs. – BeeOnRope Nov 28 '17 at 22:55
  • @zzxyz - of course that's what I want in this simple example, but my hands are tied here in the actual use-case which is decidedly not simple. The use of `shared_ptr` is widespread and embedded into the API and can't be changed without a huge effort and without breaking binary compatibility with an uncountable number of existing clients. This isn't a design question: the design is bad, I admit it. It's a pragmatic question on how to minimize the damage. – BeeOnRope Nov 28 '17 at 22:57
  • 2
    you could pass a custom, do-nothing deleter ... or use the ‘aliasing’ constructor to a dummy shared ptr ... – Massimiliano Janes Nov 28 '17 at 22:59
  • @BeeOnRope ahhh I see, apologies – zzxyz Nov 28 '17 at 23:08

1 Answers1

1

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);
}
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
  • Thanks, this actually gets me half-way there: it's source compatible but will still break binary compatibility with existing clients (since references are a different type at the ABI level). It's a good half-step though. With some linker magic it may be possible to do a gradual transition. – BeeOnRope Nov 28 '17 at 23:27