Question

Supposons que j'ai une fonction libre appelée InitFoo. Je voudrais protéger cette fonction d'être appelé plusieurs fois par accident. Sans beaucoup de réflexion j'écrit ce qui suit:

void InitFoo()
{
    {
        static bool flag = false;
        if(flag) return;
        flag = true;
    }

    //Actual code goes here.
}

Cela ressemble à une grosse verrue, cependant. InitFoo fait pas doivent conserver toute autre information d'état. Quelqu'un peut-il suggérer un moyen d'atteindre le même objectif sans la laideur?

Les macros ne comptent pas, bien sûr.

Était-ce utile?

La solution

Vous pouvez le faire avec une autre laideur:

struct InitFoo
{
     InitFoo()
     {
         // one-time code goes here
     }
};

void Foo()
{
    static InitFoo i;
}

Vous utilisez encore static, mais maintenant vous n'avez pas besoin de faire votre propre vérification de drapeau - static met déjà un drapeau et un chèque pour cela, il construit une fois que i

.

Autres conseils

Eh bien, un constructeur n'est appelée automatiquement une fois. Si vous créez une seule instance de cette classe:

class Foo
{
public:
    Foo(void)
    {
        // do stuff
    }
}

Alors //do stuff n'exécutera une fois. La seule façon de l'exécuter est deux fois pour créer une autre instance de la classe.

Vous pouvez éviter cela en utilisant un Singleton . En effet, //do stuff ne peut peut-être appelée une fois.

  

J'aimerais protéger cette fonction d'être appelé plusieurs fois par accident

Pour moi, cela ressemble à une question qui ne viendra pendant le débogage. Si tel est le cas, je voudrais simplement faire ce qui suit:

void InitFoo()
{
    #ifndef NDEBUG
       static bool onlyCalledOnce = TRUE;
       assert(onlyCalledOnce);
       onlyCalledOnce = FALSE;
    #endif

    ...
}

Le but de cette verrue particulière est facilement discernable juste en regardant, et il fera un beau, grand, échec d'assertion flashy si un programmeur fait jamais l'erreur d'appeler InitFoo plus d'une fois. Il sera également complètement disparaitre dans le code de production. (Lorsque NDEBUG est défini).

modifier : Une note rapide sur la motivation:
Appel d'une fonction d'initialisation plus d'une fois est probablement une grande erreur. Si l'utilisateur final de cette fonction a appelé à tort deux fois, ignorant tranquillement cette erreur est sans doute pas la voie à suivre. Si vous ne passez pas la route assert(), je recommande au moins le dumping un message à stdout ou stderr.

C'est exactement ce que je ferais. Vous pouvez utiliser un shuffling pointeur de fonction si vous voulez une alternative:

static void InitFoo_impl()
{
    // Do stuff.

    // Next time InitFoo is called, call abort() instead.
    InitFoo = &abort;
}

void (*InitFoo)() = &InitFoo_impl;

Avez-vous besoin aussi d'être en sécurité multi-thread? Regardez dans le modèle Singleton avec verrouillage à double contrôle (ce qui est surprenant facile de se tromper).

Si vous ne voulez pas pour cela, toute une classe d'une autre manière simple:

Dans un cpp (ne pas déclarer InitBlah dans le .h)

 // don't call this -- called by blahInited initialization
static bool InitBlah() 
{
   // init stuff here
   return true;
}
bool blahInited = InitBlah();

Personne ne peut l'appeler en dehors de cette Cpp, et il est appelé. Bien sûr, quelqu'un pourrait l'appeler dans cette Cpp - dépend de combien vous vous inquiétez qu'il est impossible par rapport pratique et documenté

.

Si vous vous souciez de l'ordre ou le faire à un moment précis, alors Singleton est probablement pour vous.

Je fais exactement ce que tout le temps avec des situations qui ont besoin que d'un temps seulement-mais-pas-valeur-faire-un-tout-classe pour. Bien sûr, il suppose que vous ne vous inquiétez pas sur les problèmes liés aux threads. Je préfixe généralement le nom de la variable « S_ » pour préciser qu'il est une variable statique.

Hmmm ... si vous ne vous opposez pas à utiliser rel="nofollow Boost , alors jetez un oeil à < a href = "http://www.boost.org/doc/libs/1_32_0/doc/html/call_once.html" rel = "nofollow noreferrer"> boost :: call_once :

namespace { boost::once_flag foo_init_flag = BOOST_ONCE_INIT; }

void InitFoo() {
    // do stuff here
}

void FooCaller() {
    boost::call_once(&foo_init_flag, InitFoo);
    // InitFoo has been called exactly once!
}

void AnotherFooCaller() {
    boost::call_once(&foo_init_flag, InitFoo);
    // InitFoo has been called exactly once!
}

Non pas que je suis très excité à ce sujet, mais c'est juste une autre façon. Objet fonction

#import <iostream>

class CallOnce {
private:
    bool called;
public:
    CallOnce() {
        called = false;
    }
    void operator()(void) {
        if (called) {
            std::cout << "too many times, pal" <<std::endl;
            return;
        }
        std::cout << "I was called!" << std::endl;
        called = true;
    }

};

int main(void) {
    CallOnce call;

    call();
    call();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top