Home > Enterprise >  How to deal uniformly with a factory returning unique_ptr and a getter returning a reference to glob
How to deal uniformly with a factory returning unique_ptr and a getter returning a reference to glob

Time:02-02

Assume there is a global Foo object,

struct Foo {
    int i;
    ~Foo() { std::cout << "gone: " << i << std::endl; }
};

Foo globalFoo{7};

that it can be retrieved via a function that returns it by reference,

Foo& getFoo() {
    return globalFoo;
}

and that there's also a factory function to make a different Foo out of thin air,

std::unique_ptr<Foo> makeFoo() {
    return std::make_unique<Foo>(5);
}

The above is unchangeable.

In client code, whether one should use makeFoo or getFoo is determined by a runtime bool.

int main()
{
    bool b{false};

    std::cin >> b;

    /* type */ foo = b
                   ? /* via getFoo */
                   : /* via makeFoo */;
} 

What is the appropriate way to deal with this scenario?

I can tell that this is not the way:

    auto& foo = b
              ? getFoo()
              : *makeFoo();

because foo is a dangling reference right after its created, as the temporary result of makeFoo(), the unique_ptr will be destoryed, thus taking the managed Foo with it.

This too is not the way:

    auto& foo = b
              ? getFoo()
              : *makeFoo().release();

because the object *makeFoo().release() is leaked, unless I manually delete it.

CodePudding user response:

You can wrap the result in shared_ptr with a deleter that does nothing in case this is a global object. Unlike for unique_ptr, deleter is not a part of the type of the smart pointer itself, so the type will be the same for both cases.

Something like this:


    auto foo = b
                   ? std::shared_ptr(&/* via getFoo */, [](Foo*){})
                   : std::shared_ptr(/* via makeFoo */);

CodePudding user response:

When calling getFoo() you does not own the object, but for makeFoo() you own it.

So you could store them in two types.

But you could make a reference to it:

unique_ptr<Foo> ufoo;
Foo* ref{};
if(b) {
  ufoo = makeFoo();
  ref = ufoo.get();
} else {
  ref = &getFoo();
}

Then take ref for further use

  • Related