Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

computed or lazy initialized global var?

27 views
Skip to first unread message

Robert A

unread,
Sep 10, 2022, 12:55:09 PM9/10/22
to
Say I have a global variable `thing` with certain properties:

thing.foo
thing.bar

If I want `thing` to be lazily initialized on first use, I could turn all my uses of it into a function...

thing().foo

Thing &thing() {
if (!_instance) { _instance = new Thing; }
return *_instance;
}

Is there a way to get the same effect without the parens? Ie, so I can say `thing.foo`. I'm craving syntactic sugar.

Clang has an extension (__declspec) where you can put computed properties on a class. [1] I don't have a problem using a compiler extension, but I don't know of one do a similar thing with a global.

[1]: https://stackoverflow.com/a/49230152/327572







Richard Damon

unread,
Sep 10, 2022, 1:40:26 PM9/10/22
to
Evil preprocessor hack

#define thing thing_()

and then define Thing &thing_()



Richard Damon

unread,
Sep 10, 2022, 1:43:34 PM9/10/22
to
On 9/10/22 12:55 PM, Robert A wrote:
You could also define a class ThingProxy with a conversion function from
ThingProxy to Thing that creates the object if not already created.

The "ThingProxy" will be created at startup, but that is a trivial, the
Thing won't be created until used.

Robert A

unread,
Sep 10, 2022, 2:00:26 PM9/10/22
to
On Saturday, September 10, 2022 at 12:43:34 PM UTC-5, Richard Damon wrote:
> You could also define a class ThingProxy with a conversion function from
> ThingProxy to Thing that creates the object if not already created.
>
> The "ThingProxy" will be created at startup, but that is a trivial, the
> Thing won't be created until used.

I was trying that, but haven't gotten it to work exactly yet. The code below is close. Do you have a way to get that last line to work?

struct Thing {
Thing() { cout << "Thing()" << endl; }
string foo = "foo value";
};
Thing *_thing = nullptr;
struct LazyThing {
operator const Thing&() {
cout << "op(Thing&)" << endl;
if (!_thing) {
_thing = new Thing;
}
return *_thing;
}
};
LazyThing thing;
int main()
{
// This works, but the cast syntax defeats the point.
cout << ((Thing)thing).foo << endl;
const Thing &t = thing;
cout << t.foo << endl; // works
cout << thing.foo << endl; // won't compile
}

Robert A

unread,
Sep 10, 2022, 2:08:19 PM9/10/22
to
On Saturday, September 10, 2022 at 1:00:26 PM UTC-5, Robert A wrote:
> struct Thing { ...

Sorry about the lack of indentation. I haven't posted here before. Apparently this browser-based google groups text editor just deletes the indentation I put at the start of a line.

Ben Bacarisse

unread,
Sep 10, 2022, 3:36:08 PM9/10/22
to
Robert A <robert.a...@gmail.com> writes:

> Say I have a global variable `thing` with certain properties:
>
> thing.foo
> thing.bar
>
> If I want `thing` to be lazily initialized on first use, I could turn
> all my uses of it into a function...
>
> thing().foo
>
> Thing &thing() {
> if (!_instance) { _instance = new Thing; }
> return *_instance;
> }
>
> Is there a way to get the same effect without the parens? Ie, so I can
> say `thing.foo`. I'm craving syntactic sugar.

If you are prepared to forego the dot and use -> instead, this pattern

class Thing {
struct ActualThing {
int foo;
int bar;
} actual_thing;
public:
const ActualThing *operator->() {
// Do what you like here to set up 'actual_thing'.
return &actual_thing;
}
};

gives you a function call at the time the member is accessed. You
could, as I think you were trying elsewhere, have a private pointer to
an 'actual_thing', and use that to decide if it needs to be allocated,
but that just means you need more machinery. There are lots of simpler
ways to ensure that 'actual_thing' gets initialised only once.

But I am tempted to ask what you are really doing. It looks odd to make
an object before the members can be usefully initialised.

--
Ben.

Robert A

unread,
Sep 10, 2022, 4:34:16 PM9/10/22
to
On Saturday, September 10, 2022 at 2:36:08 PM UTC-5, Ben Bacarisse wrote:
> If you are prepared to forego the dot and use -> instead, this pattern [...]
> [...] There are lots of simpler ways to ensure that 'actual_thing' gets initialised only once.
>
> But I am tempted to ask what you are really doing. It looks odd to make
> an object before the members can be usefully initialised.

Partly I'm just trying to learn what's possible in the language (C++). I've used lazy init in other languages for things that may or may not be needed as the program runs. In the real example that I'm working on currently, I don't really need the lazy init, because this `thing` is always used. The actual variable is called `loczn` and it holds properties and methods that give me localized strings throughout the UI code. I need to set it once as the program starts up, and reset to a different subclass it if the user's language preference changes. Another point is that I'd like it to have virtual functions on this thing (different languages, different subclasses). So I liked the idea of `thing`/`loczn` being a _reference_.




0 new messages