Usa l'oggetto senza nome per invocare il metodo o no?

1

Se ho una classe con solo un metodo pubblico. Quando uso questa classe, è bene usare l'oggetto senza nome per invocare il suo metodo?

normale:

TaxFileParser tax_parser(tax_file_name);
auto content = tax_parser.get_content();

o versione dell'oggetto senza nome:

auto content = TaxFileParser(tax_file_name).get_content();

Perché ho detto che dovremmo evitare il più temporaneamente possibile. Se l'oggetto tax_parser viene utilizzato una sola volta, posso chiamarlo temporaneo e provare ad eliminarlo?

Qualsiasi suggerimento sarà utile.

    
posta Chen OT 26.05.2014 - 16:42
fonte

3 risposte

3

L'oggetto temporaneo viene comunque creato, indipendentemente dal fatto che gli sia stato assegnato un nome o meno. Le tue due linee sono equivalenti.

Se esiste un solo metodo pubblico, chiederei perché si tratta di una classe. Può essere gestito da una funzione con tax_file_name come parametro? Quindi non avresti un oggetto temporaneo altrimenti inutile.

class TaxFileParser
{
   public:
     static whatever_t get_content(const std::string& file)
     {
       return result_from_file_in_question();
     }
};

auto content = TaxFileParser::get_content(tax_file_name);
    
risposta data 26.05.2014 - 16:58
fonte
4

Posizionare un oggetto in una variabile perché ti è stato "detto che dovremmo evitare il più temporaneo possibile" è come usare variabili statiche perché ti è stato detto che i singleton sono cattivi - non stai davvero evitando il problema, solo il codice odore che viene fornito con la forma più comune del problema.

Come dice nvoigt, se vuoi evitare del tutto questo problema, devi cambiare il metodo in qualcosa che non crea oggetti. Tuttavia, potrebbe non essere possibile (forse non è possibile modificare il codice sorgente dell'oggetto?) O ragionevole (forse la classe ha altri metodi, e non si vuole rovinare la progettazione) per farlo. In tal caso, credo che il primo approccio (oggetto temporaneo senza nome) sia migliore.

La principale differenza tra i due approcci è quando verrà chiamato il distruttore dell'oggetto temporaneo. Se si tratta di un oggetto temporaneo con nome, verrà chiamato alla fine dell'ambito. Se si tratta di un oggetto temporaneo senza nome, verrà chiamato dopo la chiamata a get_content() , quando l'oggetto non è più necessario.

Ho giocato un po 'con objdump e ho scoperto che se metti solo queste due (o una) riga in una funzione, l'unica differenza tra i due è che nella versione senza nome l'oggetto viene distrutto prima il risultato di get_content viene spostato a content mentre nella versione con nome succede dopo.

Tuttavia, quando ho aggiunto un'istruzione per stampare content dopo quelle righe, le cose diventano un po 'più complicate. La versione nominata ha prodotto il codice per chiamare il distruttore due volte - una volta alla fine della funzione, e una volta in un punto successivo che non viene mai eseguito ! O, dovrei dire, non viene mai eseguito nel flusso regolare della funzione .

Non ho familiarità con il modo in cui C ++ funziona in assembly-wise, ma presumo che questo abbia a che fare con la gestione delle eccezioni - quando il metodo di stampa (beh, operatore ...) lancia un'eccezione, il meccanismo di srotolamento dello stack ha bisogno essere in grado di chiamare i distruttori, quindi usa quel codice.

Per verificare questa ipotesi, ho aggiunto un'istruzione throw a get_content , e come mi aspettavo ora anche la versione senza nome ha ottenuto quel segmento di codice, poiché ora può anche ottenere un'eccezione prima che avvenga la normale distruzione . Ma ancora - gcc è riuscito a ottimizzarlo quando non era necessario!

Quindi, in conclusione, scegli la versione senza nome! I compilatori moderni sono molto intelligenti ma non riescono a leggerti nella mente, quindi i suggerimenti che fornisci loro sulle tue intenzioni sono il lavoro migliore che possono fare. L'uso della versione senza nome induce all'ottimizzatore che è necessario solo l'oggetto per get_content ed è libero di eliminarlo successivamente e ottimizzare le cose in questo modo. Più cose accadono tra la creazione di un oggetto e la sua distruzione, più è difficile per l'ottimizzatore ragionare sul suo ruolo.

    
risposta data 26.05.2014 - 18:42
fonte
1

Le variabili temporanee sono anche peggiori dei valori senza nome temporanei. Per usare una variabile temporanea, devi trovare un nome per questo e tutti quelli che leggono il codice devono leggere quel nome, ricordare cosa significa e controllare la sua estensione.

Ci sono buoni motivi per implementare le funzionalità di una classe. Ma se ha solo un metodo chiamato solo una volta su un'istanza, la classe è un dettaglio di implementazione. L'API pubblica dovrebbe essere una funzione come:

whatever_t parse_tax(string const &tax_file_name) {
    return TaxFileParser(tax_file_name).get_content();
}

C ++ è una lingua multi-paradigmatica. Non richiede che tutto sia in una classe. Quindi metti le cose solo se ha un significato reale.

    
risposta data 27.05.2014 - 00:21
fonte

Leggi altre domande sui tag