(possibly related to How to implement the C ++ method, which creates a new object, and returns a link to it that has something else, but, by the way, contains almost exactly the same code)
I would like to return a link to a static local element from a static function. I can make it work, of course, but it's less cute than I would like.
Can this be improved?
Background
I have several classes that do nothing but receive or initialize a resource in a well-defined form and reliably, and free it. They donโt even need to know a lot about the resource itself, but the user can still request some information in some way.
This, of course, is trivial:
struct foo { foo() { } ~foo(){ } }; int main() { foo foo_object;
Trivial Alternatively, this will also work well:
#include <scopeguard.h> int main { auto g = make_guard([](){ /* blah */}, [](){ /* un-blah */ }); }
Except for now, requesting stuff is a little more complicated, and it's less cute than I like. If you prefer Stroustrup rather than Alexandrescu, you can enable GSL instead and use some mix including final_act . Whatever.
Ideally, I would like to write something like:
int main() { auto blah = foo::init(); }
If you return a link to an object you can request if you want to do this. Or ignore it or something else. I immediately thought: โIt is easy that only Mayer Singleton is hiding. Thus:
struct foo {
What is it! The dead are simple and perfect. foo is created when you call init , you return a bar , which you can request for statistics, and this is a link so that you are not the owner, and foo automatically cleared at the end.
Besides...
Problem
Of course, this cannot be so simple, and anyone who has ever used a range based on auto knows that you need to write auto& if you don't want surprises. But alas, auto looked so completely innocent that I did not think about it. In addition, I explicitly return the link, so auto might possibly capture, but the link!
Result: a copy is made (from what? Presumably from the returned link?), Which, of course, has a limited lifespan. The instance constructor is called by default (harmless, does nothing), eventually the copy goes out of scope, and contexts go out in the middle of the operation, the material stops working. At the end of the program, the destructor is called again. Kaboooom. Yes, how did this happen.
The obvious (well, not so obvious in the first second!) Solution is to write:
auto& blah = foo::init();
It works and works great. The problem is solved, except ... except that it is ugly, and people can accidentally do it wrong, like me. Can't we do it without requiring an extra ampersand?
It may also work to return shared_ptr , but it will require unnecessary allocation of dynamic memory, and even worse, it would be "wrong" in my perception. You do not share ownership, you are simply allowed to look at what owns someone else. Raw pointer? Correct semantics, but ... ugh.
By deleting the copy constructor, I can prevent innocent users from starting in zabr. trap (this will result in a compiler error).
This, however, is still less beautiful than we would like. There must be a way of linking "This return value should be used as a reference" to the compiler? Something like return std::as_reference(b); ?
I thought of some reason related to the "moving" of the object without moving it, but not only the compiler will almost certainly not allow you to move the static local file at all, but if you manage to do this, you either have changed ownership, or using constructor move "fake move" call the destructor twice again. So no solution.
Is there a better, more beautiful way, or do I just need to live with an auto& record?