What's a good pattern to calculate a variable only when it is used the first time? [closed]

Solution 1:

Whereas std::string has empty value which might mean "not computed", you might use more generally std::optional which handle empty string and non default constructible types:

void PrintToGameMasters()
{
    std::optional<std::string> message;

    for (Player* player : GetAllPlayers()) {
       if (player->IsGameMaster()) {
           if (!message) {
              message = GetComplicatedDebugMessage();
           }
           player->SendMessage(*message);
       }
    }
}

Solution 2:

Use data-oriented design; keep two lists of players: game masters and non-game masters (or all players like you have now + a separate vector of pointers to game-masters only).

void PrintToGameMasters()
{
    auto players = GetGameMasters(); // Returns ONLY game master players
    if (players.begin() != players.end()) {
        std::string message = GetComplicatedDebugMessage();
        for (Player* player : players) {
            player->SendMessage(message);
        }
    }
}

The goal is to minimize if-statements inside loops.

Optimize for the most common case, not the most generic one; the most common case is that a player is not a game master; so avoid looping over them.


P.S. Since you're developing a game, I want to add this link to Mike Acton's cppcon talk which you might find interesting.

Solution 3:

Some good ideas here, but I like to keep it a bit more simple:

void PrintToGameMasters()
{
    std::string message;

    for (Player* player : GetAllPlayers())
    {
       if (player->IsGameMaster())
       {
           if (message.empty())
              message = GetComplicatedDebugMessage();

           player->SendMessage(message);
       }
    }
}

Everybody can follow this, and it's cheap as chips… plus it's easy as pie to debug.

Solution 4:

You can use std::call_once with a lambda to call the function the first time you find a game master like

void PrintToGameMasters()
{
    std::once_flag of;
    std::string message;
    for (Player* player : GetAllPlayers())
       if (player->IsGameMaster())
       {
           std::call_once(of, [&](){ message = GetComplicatedDebugMessage(); });
           player->SendMessage(message);
       }
}