Costruttore di tipo int

Considerando il costo, questi casi sono gli stessi?

// case 1 int a = 5; // case 2 int a (5); // case 3 int a; a = 5 

Il primo e il secondo sono esattamente gli stessi di entrambi sono inizializzazione . Il terzo è diverso, poiché questo è un compito . Queste differenze sono conformi allo standard C ++. Tuttavia, il compilatore può considerare tutti e tre uguali!

Le tre syntax sono diverse, portami con me mentre uso un tipo definito dall’utente invece di int, tornerò su int dopo.

 T a(5); // Direct initialization T b = 5; // Implicit conversion (5->tmp) + copy-initialization T c; c = 5; // Default initialization + assignment 

Nel primo caso l’object a è costruito per mezzo di un costruttore che accetta un int o un tipo che può essere convertito implicitamente da int .

 struct T { T( int ); // T a(5) will call this directly }; 

Nel secondo caso, un object temporaneo di tipo T viene creato da una conversione implicita da int , e quindi quel temporaneo viene utilizzato per copiare il costrutto b . Il compilatore è autorizzato a ottimizzare il codice e ad eseguire solo la conversione implicita al posto dell’object finale (invece di utilizzarlo per creare il temporaneo.) Ma tutte le restrizioni devono essere verificate :

 class T { T( T const & ); public: explicit implicit T( int ); }; int main() { T b = 5; // Error 1: No implicit conversion from int to T. // Fix: remove the `explicit` from the constructor // Error 2: Copy constructor is not accessible } 

Il terzo caso è la costruzione predefinita seguita da assegnazione. I requisiti del tipo sono che può essere costruito in modo predefinito (c’è un costruttore senza argomenti, o non esiste alcun costruttore definito dall’utente e il compilatore lo definirà implicitamente). Il tipo deve essere assegnabile da int o deve esserci una conversione implicita da int a un tipo U che può essere assegnato a T Come vedete, i requisiti per il tipo nei casi di albero differiscono.

Oltre alla semantica delle diverse operazioni, c’è un’altra importante differenza, non tutte possono essere utilizzate in tutti i contesti. In particolare, in una lista di inizializzazione in una class non è ansible utilizzare la versione implicita di conversione + copia di inizializzazione e si può solo avere la prima metà del costrutto predefinito + assegnare .

 // OK // error // ok but different struct test { struct test { struct test { T x; T x; T x; test(int v) : x(v) {} test(int v) : x=5 {} test( int v ) { x = v; } 

Nel primo caso l’attributo x è inizializzato direttamente con il valore v . Il secondo caso è un errore di syntax. Il terzo caso viene inizialmente inizializzato e quindi assegnato al corpo del costruttore.

Tornando all’esempio int , tutti i requisiti sono soddisfatti dal tipo, quindi non c’è quasi nessuna differenza sul codice che il compilatore genera per i tre casi, ma ancora non è ansible utilizzare int b = 5; versione all’interno di un elenco di inizializzazione per inizializzare un attributo intero. Inoltre, se una class ha un attributo membro che è un numero intero costante, non è ansible utilizzare l’equivalente di int c; c =5; int c; c =5; (terza colonna sopra) quando l’attributo membro diventa const quando entra nel blocco costruttore, cioè x = v; sopra sarebbe provare a modificare una costante e il compilatore si lamenterà.

Per quanto riguarda il costo che ciascuno ha, se possono essere utilizzati, comportano lo stesso costo per un int (per qualsiasi tipo di POD), ma non così per i tipi definiti dall’utente che hanno un costruttore predefinito, nel qual caso T c; c = 5; T c; c = 5; sosterrà il costo di costruzione di default seguito dal costo di assegnazione . Negli altri due casi, lo standard afferma esplicitamente che il compilatore può generare lo stesso codice esatto (una volta controllati i vincoli).

Per i primi due, non ci sarà differenza.

Da documenti standard, 8.5.11 ,

La forma di inizializzazione (usando parentesi o =) è generalmente insignificante, ma è importante quando l’inizializzatore o l’ quadro inizializzata ha un tipo di class; vedi sotto. Un inizializzatore tra parentesi può essere un elenco di espressioni solo quando l’ quadro inizializzata ha un tipo di class.

Il terzo non è un’inizializzazione ma un compito.

E considerando il costo,

Nei primi due casi, si sta creando un numero intero con un valore 5.

Nel terzo caso, stai creando un numero intero con un valore non definito e lo sostituisci con 5 ..

Se si utilizza un compilatore di ottimizzazione, verranno tutti compilati con lo stesso codice. Quindi hanno tutti lo stesso costo.

Sì, tutti valutano esattamente la stessa rappresentazione assemblatore. È ansible testare questo ad es. Con GCC scrivendo una funzione dummy e quindi producendo l’output dell’assembler: g++ -S file.cxx -o file.s