È sicuro definire una funzione di utilità per uso locale nel mio file .cpp?

0

Il codice elencato di seguito ha lo scopo di calcolare alcuni dati di rotazione che verranno successivamente utilizzati nel mio codice di rendering.

renderer.cpp:

rendered_image renderer::common_tasks(render_info const& info) {
    //info.radius is a float, info.min_image_size is an int calculated by taking the minimum
    //of info.image_width and info.image_height
    cl_float raw_delta = 2.f * info.radius / info.min_image_size;
    //cl_float4 is functionally a wrapper around float[4].
    //info.rotation is a float value representing the rotation in degrees
    cl_float4 final_deltas{
        cos(to_radians(info.rotation)) * raw_delta,
        sin(to_radians(info.rotation)) * raw_delta,
        -sin(to_radians(info.rotation)) * raw_delta,
        cos(to_radians(info.rotation)) * raw_delta
    };
    //Other, irrelevant code
    /*...*/
}

Ma ovviamente volevo ripulire un po 'il codice, quindi l'ho riscritto in questo modo:

renderer.cpp:

cl_float4 get_deltas(render_info const& info) {
    //info.radius is a float, info.min_image_size is an int calculated by taking the minimum
    //of info.image_width and info.image_height
    cl_float raw_delta = 2.f * info.radius / info.min_image_size;
    //cl_float4 is functionally a wrapper around float[4].
    //info.rotation is a float value representing the rotation in degrees
    cl_float4 final_deltas{
        cos(to_radians(info.rotation)) * raw_delta,
        sin(to_radians(info.rotation)) * raw_delta,
        -sin(to_radians(info.rotation)) * raw_delta,
        cos(to_radians(info.rotation)) * raw_delta
    };
    return final_deltas;
}

rendered_image renderer::common_tasks(render_info const& info) {
    cl_float4 final_deltas = get_deltas(info);
    //Other, irrelevant code
    /*...*/
}

Ora, tuttavia, ho una funzione dichiarata globalmente get_deltas che esiste solo in questo file .cpp. Così com'è, questo codice viene compilato e eseguito normalmente, ma ci sono dei rischi significativi per scrivere codice come questo? Dovrei annidare la funzione in un namespace o dichiararla privata nella classe renderer ? So per certo che non avrò mai bisogno di usare get_deltas in nessun altro posto nel mio codice: questo cambia se questo è un uso buono o cattivo di questo stile di codice?

    
posta Xirema 13.02.2017 - 21:11
fonte

3 risposte

13

In linea di principio, i metodi privati o locali devono sempre essere private membri della classe o static funzioni locali. Dichiarando una funzione come statica diventa scope del file e il linker genera un errore se si tenta di utilizzarlo al di fuori dell'ambito del file in cui è stato dichiarato.

Puoi anche utilizzare lo spazio dei nomi anonimo per ottenere la stessa cosa che è più prolissa ma preferibile in alcuni posti.

Uno dei motivi principali è che, sebbene tu possa mai intendere utilizzare get_deltas altrove, qualcun altro potrebbe a volte nella vita del programma, possibilmente come errore di battitura, e poi c'è una ragionevole possibilità che il programma compilerà e collegherà senza errori, (dovresti ricevere un avviso) , ma avrà un bug oscuro e difficile da localizzare.

    
risposta data 13.02.2017 - 21:22
fonte
4

Oltre alla risposta di Steve Barnes:

  1. Rendere la funzione un metodo privato è il modo OO pulito; Preferirei questo.
  2. L'uso di uno spazio dei nomi anonimo è il "nuovo" modo C ++; Lo sto usando più e più volte, e. g. per interni locali (costanti, ecc.) che potrebbero non trapelare all'esterno e sono mai e poi mai pensati per essere usati dalle classi derivate. Non è ancora pulito OO, però.

    namespace {
        const int myMagicNumber = 0xdeadbeef;
    }
    
  3. L'utilizzo di static è il vecchio modo C; nei miei progetti, a seconda del contesto, di solito trasferisco queste strutture in un namespace anonimo o ne faccio un membro quando ne trovo uno.
risposta data 14.02.2017 - 10:26
fonte
1

In generale la mia risposta sarebbe la stessa della risposta di Steve Barnes, con una aggiunta:

Se è necessario eseguire test unitari sulla funzione secondaria che è stata ora estratta (ad esempio con GTest), sarà necessario renderlo richiamabile dall'esterno. Ciò significa che il prototipo di funzione deve essere dichiarato in un file *.h . Inoltre, non può essere una funzione privata all'interno di una classe e non può trovarsi all'interno di uno spazio dei nomi anonimo.

La questione se debba essere un test unitario la funzione pubblicabile pubblicamente o la funzione di utilità ora estratta è meglio lasciarti, dato che hai la migliore conoscenza del tuo progetto. Esistono linee guida generali che sono trattate nella maggior parte dei libri di testo di test unitari.

    
risposta data 13.02.2017 - 22:18
fonte

Leggi altre domande sui tag