Domanda

Supponiamo di avere una funzione gratuita chiamata InitFoo.Vorrei proteggere questa funzione dall'essere chiamata più volte per sbaglio.Senza pensarci troppo ho scritto quanto segue:

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

    //Actual code goes here.
}

Sembra una grossa verruca, però. InitFoo fa non necessità di preservare qualsiasi altra informazione sullo stato.Qualcuno può suggerire un modo per raggiungere lo stesso obiettivo senza la bruttezza?

Le macro non contano, ovviamente.

È stato utile?

Soluzione

Puoi farlo con qualche bruttezza diversa:

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

void Foo()
{
    static InitFoo i;
}

Lo stai ancora usando static, ma ora non è più necessario eseguire il controllo dei flag - static inserisce già un flag e un controllo, quindi costruisce solo i una volta.

Altri suggerimenti

Bene, un costruttore viene chiamato automaticamente una sola volta. Se si crea una singola istanza di questa classe:

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

Poi //do stuff verrà eseguito solo una volta. L'unico modo per eseguire due volte è quello di creare un'altra istanza della classe.

È possibile evitare questo utilizzando un Singleton . In effetti, //do stuff può solo eventualmente essere chiamato una volta.

  

mi piacerebbe per proteggere questa funzione da essere chiamato più volte per caso

Per me, questo suona come un problema che non potrà che venire durante il debug. Se questo è il caso, vorrei semplicemente fare quanto segue:

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

    ...
}

Lo scopo di questa particolare verruca è facilmente individuabile solo guardando, e causerà una bella, grande, errore di asserzione appariscente se un programmatore fa mai l'errore di chiamare InitFoo più di una volta. Sarà anche completamente sparire nel codice di produzione. (Quando NDEBUG è definito).

modifica : Una breve nota sulla motivazione:
Chiamare una funzione init più di una volta è probabilmente un grosso errore. Se l'utente finale di questa funzione ha erroneamente chiamato due volte, tranquillamente ignorare questo errore non è probabilmente la strada da percorrere. Se non si va via assert(), mi sento di raccomandare almeno di dumping un messaggio a stdout o stderr.

Questo è esattamente come lo farei. Si potrebbe usare un po 'di puntatore a funzione rimescolamento se si vuole un'alternativa:

static void InitFoo_impl()
{
    // Do stuff.

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

void (*InitFoo)() = &InitFoo_impl;

Hai anche bisogno di essere multi-thread-safe? Guardate nel pattern Singleton con bloccaggio doppio controllo (che è sorprendente facile da sbagliare).

Se non si desidera una classe intera per questo, un altro modo semplice è:

In un cpp (non dichiarare InitBlah nel .h)

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

Nessuno può chiamare al di fuori di questo cpp, e viene chiamato. Certo, qualcuno potrebbe chiamarlo in questo cpp - dipende da quanto vi preoccupate che è impossibile contro scomodo e documentato

.

Se vi preoccupate per ordine o farlo in un momento specifico, poi Singleton è probabilmente per voi.

Lo faccio esattamente che tutto il tempo con le situazioni che hanno bisogno che una volta sola-ma-non-valore-making-a-tutta-class-per. Naturalmente, si presuppone che non preoccuparsi di problemi di filo-related. Io di solito prefisso il nome della variabile con "s_" per mettere in chiaro che si tratta di una variabile statica.

Hmmm ... se non contrario a utilizzare Boost , allora date un'occhiata a < 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 che io sono molto eccitato a riguardo, ma questo è solo un altro modo:. Oggetto funzione

#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();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top