Devo usare una tabella di salto o un'istruzione switch case per funzioni simili, ma potrei avere alcuni parametri che non sono rilevanti [chiuso]

2

Ho avuto una ENORME istruzione switch/case , che ho convertito per usare una funzione dispatch table usando una lista di enum per l'indice.

Il mio collega (che sta facendo una revisione del codice su questo cambiamento) ha convenuto che dovrebbe essere suddiviso in diverse funzioni, ma c'è stata una modifica successiva che ha richiesto che alcuni parametri non fossero utilizzati in tutte le funzioni.

Il codice non è ancora stato finalizzato e il suo suggerimento è che al posto di dispatch table , io uso un switch/case che chiama le funzioni. La sua logica è che poiché non tutte le funzioni useranno tutti i parametri, che chiamare ogni singola funzione con firme leggermente diverse sarebbe meglio che usare una singola firma di funzione per tutte le singole funzioni.

Non sono troppo sfavorevole a questa idea, ma non sono davvero convinto che sia davvero un passo avanti. I parametri sono tutti i tipi di POD e solo gli ultimi due che vengono inoltrati non sono necessariamente utilizzati. Quindi non c'è un vero problema di prestazioni, anche se è stato chiamato molto, il che non è (richiede che l'utente preme un pulsante, rendendo il tempo di spedizione insignificante rispetto a).

Questo è approssimativamente il layout corrente che ho migrato:

enum FindWhere_e : int
{
    FindInA = 0, // Find Where
    FindInD = 1,
    FindInC = 2,
    FindInE = 3,
    FindInH = 4,
    FindInI = 5,
    FindInJ = 6,
    FindInK = 7,
    FindInL = 8,
    FindInM = 9,
    FindInB = 10,
    FindInN = 11,
    FindInO = 12,
    FindInP = 13,
    FindInQ = 14,
    FindInF = 15,
    FindInR = 16,
    FindInG = 17,
};

BOOL Paragraph::DoSearch(IParaIdxC ipara, int ichar, FindReplaceData *frData, BOOL firstpara, BOOL lastpara, int *nchanges, CDocEnvironment& docEnv, bool allowRedisplay, Section *pSection, CTextWindow* textWindow)
{
    typedef decltype(&Paragraph::DoSearch) vtableElement_t;
    static vtableElement_t const jumpTable[] =
    {
        &Paragraph::DoSearch_FindInA,        // FindInA
        &Paragraph::DoSearch_FindIn_D_C_B_O, // FindInD
        &Paragraph::DoSearch_FindIn_D_C_B_O, // FindInC
        &Paragraph::DoSearch_FindInE,        // FindInE
        &Paragraph::DoSearch_FindInH,        // FindInH
        &Paragraph::DoSearch_FindInI,        // FindInI
        &Paragraph::DoSearch_FindInJ,        // FindInJ
        &Paragraph::DoSearch_FindIn_K_L,     // FindInK
        &Paragraph::DoSearch_FindIn_K_L,     // FindInL
        &Paragraph::DoSearch_FindInM,        // FindInM
        &Paragraph::DoSearch_FindIn_D_C_B_O, // FindInB
        &Paragraph::DoSearch_FindInN,        // FindInN
        &Paragraph::DoSearch_FindIn_D_C_B_O, // FindInO
        &Paragraph::DoSearch_FindInP,        // FindInP
        &Paragraph::DoSearch_FindInQ,        // FindInQ
        &Paragraph::DoSearch_FindInF,        // FindInF
        &Paragraph::DoSearch_FindInR,        // FindInR
        &Paragraph::DoSearch_FindInG,        // FindInG
    };
    // frData->Where is of type FindWhere_e
    if ((unsigned int)(frData->Where) < std::extent<decltype(jumpTable)>::value)
    {
        return (this->*jumpTable[frData->Where])(ipara, ichar, frData, firstpara, lastpara, nchanges, docEnv, allowRedisplay, pSection, textWindow);
    }
    ASSERT(false); // Not handling an unregistered find type in the dispatch table.
    return FALSE;
}

Quindi mi piacerebbe sapere se c'è qualche ragione per usarne uno sull'altro o se davvero non ha importanza dal punto di vista del design. Personalmente non trovo né più chiaro da leggere.

    
posta Adrian 08.12.2015 - 23:51
fonte

2 risposte

2

Bene, esaminiamo prima l'argomento delle prestazioni:

  • Il tuo dispatcher ha gli stessi argomenti delle funzioni di implementazione.
  • Tutti gli argomenti sono banalmente copiabili.
  • Il tuo dispatcher non deve eseguire alcuna pulizia dopo l'invio e restituisce gli argomenti delle funzioni di implementazione richiamati verbatim.

Pertanto, la tua implementazione dovrebbe eseguire un'ottimizzazione delle chiamate tail, se non li integra semplicemente.
È abbastanza probabile che il compilatore sia più incline a integrare le chiamate nell'istruzione switch rispetto alla chiamata indicizzata, il che potrebbe invertire chi ha il vantaggio.
Come sempre, se ti interessa davvero, misura!

A parte questo, anche se decidete di consentire argomenti di produzione fuori range (come un modo per renderlo a prova di futuro ??), considerate di mettere il caso inaspettato in un ifblocco, come spesso questo porta a prestazioni migliori.

BOOL Paragraph::DoSearch(IParaIdxC ipara, int ichar, FindReplaceData *frData,
    BOOL firstpara, BOOL lastpara, int *nchanges, CDocEnvironment& docEnv,
    bool allowRedisplay, Section *pSection, CTextWindow* textWindow)
{
    static const decltype(&Paragraph::DoSearch) jumpTable[] = {
        ... omitted
    };
    if((unsigned)frData->Where >= std::extent<decltype(jumpTable)>()) {
        assert(0);
        return FALSE;
    }
    return (this->*jumpTable[frData->Where])(ipara, ichar, frData, firstpara,
        lastpara, nchanges, docEnv, allowRedisplay, pSection, textWindow);
}
    
risposta data 09.12.2015 - 00:42
fonte
1

Dal momento che sono state introdotte alcune funzioni che accettano un numero diverso di parametri rispetto al resto, non hai più una situazione perfettamente uniforme nelle tue mani.

Non è un peccato mortale cercare di calzare una situazione non perfettamente uniforme in una situazione perfettamente uniforme, ma ho una leggera avversione nel fare quel genere di cose: se c'è una mancanza di uniformità, non mi piace fingendo che ci sia uniformità.

E il futuro di solito dimostra che nel corso del tempo, la piccola mancanza di uniformità tende a diventare una crescente mancanza di uniformità, richiedendo più hack e trucchi per cercare di mantenere l'illusione di uniformità.

Quindi, vorrei andare con il caso switch.

(Non sto menzionando le considerazioni sulle prestazioni, poiché hai già affermato che le prestazioni non sono un problema.)

    
risposta data 09.12.2015 - 01:38
fonte

Leggi altre domande sui tag