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