Cosa significano le seguenti frasi in C ++: zero, default e inizializzazione di valore?


190

Cosa significano le seguenti frasi in C ++:

  • zero inizializzazione,

  • inizializzazione predefinita e

  • valore di inizializzazione

Cosa dovrebbe sapere uno sviluppatore C ++ su di loro?


1
Questo è legato a (ma non identico a) stackoverflow.com/questions/620137/…
Steve Jessop,

20
C'è più! L'elenco completo delle inizializzazioni: valore, diretto, copia, elenco (nuova introduzione C ++ 11), aggregato, riferimento, zero, costante e predefinito; en.cppreference.com/w/cpp/language/initialization li elenca tutti con esempi :)
legends2k

Risposte:


65

Una cosa da capire è che "l'inizializzazione del valore" è nuova con lo standard C ++ 2003 - non esiste nello standard originale del 1998 (penso che potrebbe essere l'unica differenza che è più di un chiarimento). Vedi la risposta di Kirill V. Lyadvinsky per le definizioni direttamente dallo standard.

Vedi questa risposta precedente sul comportamento di operator newper dettagli sul diverso comportamento di questo tipo di inizializzazione e quando iniziano (e quando differiscono da c ++ 98 a C ++ 03):

Il punto principale della risposta è:

A volte la memoria restituita dal nuovo operatore viene inizializzata, a volte non dipende dal tipo di POD che stai rinnovando o se è una classe che contiene membri POD e utilizza un costruttore predefinito generato dal compilatore .

  • In C ++ 1998 ci sono 2 tipi di inizializzazione: zero e default
  • In C ++ 2003 è stato aggiunto un terzo tipo di inizializzazione, inizializzazione del valore.

Per non dire altro, è piuttosto complesso e quando i diversi metodi entrano in gioco sono sottili.

Una cosa di cui bisogna essere consapevoli è che MSVC segue le regole C ++ 98, anche in VS 2008 (VC 9 o cl.exe versione 15.x).

Il frammento seguente mostra che MSVC e Digital Mars seguono le regole C ++ 98, mentre GCC 3.4.5 e Comeau seguono le regole C ++ 03:

#include <cstdio>
#include <cstring>
#include <new>

struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

int main()
{
    char buf[sizeof(B)];
    std::memset( buf, 0x5a, sizeof( buf));

    // use placement new on the memset'ed buffer to make sure 
    //  if we see a zero result it's due to an explicit 
    //  value initialization
    B* pB = new(buf) B();   //C++98 rules - pB->m is uninitialized
                            //C++03 rules - pB->m is set to 0
    std::printf( "m  is %d\n", pB->m);
    return 0;
}

1
Non è importante int, ma m()sulla terza riga il valore inizializza m. Importante se si int m;passa a B m;. :)
Johannes Schaub - litb

Giusto - Ae Cnon sono usati in questo esempio (sono riportati dall'altra risposta collegata). Anche se C ++ 98 e C ++ 03 usano una terminologia diversa quando descrivono come Ae Csono costruiti, il risultato è lo stesso in entrambi gli standard. Si struct Btraduce solo in un comportamento diverso.
Michael Burr,

1
quello che intendevo dire è che se cambi C in struct C { C() : m() {}; ~C(); B m; };, allora avrai m.m0. Se l'inizializzazione di default è mcome dici C ++ 03, allora m.mnon verrà inizializzata come in C ++ 98.
Johannes Schaub - litb,

1
Ulteriori commenti interessanti sulla gestione MSVC di questa funzione: stackoverflow.com/questions/3931312/…
Brent Bradburn,

Quale inizializzazione ha luogo quando dichiari il tuo tipo come variabile locale, cioè nello stack?
André Puel,

89

C ++ 03 Standard 8.5 / 5:

A zero inizializzare un oggetto di mezzi tipo T:
- se T è un tipo scalare (3.9), l'oggetto viene impostato al valore 0 (zero) convertito a T;
- se T è un tipo di classe non sindacale, ciascun membro di dati non statico e ciascun oggetto secondario di classe base è inizializzato a zero;
- se T è un tipo di unione, il primo membro di dati con nome dell'oggetto viene inizializzato con zero;
- se T è un tipo di array, ogni elemento è inizializzato a zero;
- se T è un tipo di riferimento, non viene eseguita l'inizializzazione.

Inizializzare per default un oggetto di tipo T significa:
- se T è un tipo di classe non POD (clausola 9), viene chiamato il costruttore predefinito per T (e l'inizializzazione non è corretta se T non ha un costruttore predefinito accessibile);
- se T è un tipo di array, ogni elemento è inizializzato per impostazione predefinita;
- in caso contrario, l'oggetto viene inizializzato con zero.

Per valore-inizializzare un oggetto di mezzi tipo T:
- se T è un tipo di classe (clausola 9) con un costruttore dall'utente dichiarato (12.1), quindi il costruttore predefinito per T è chiamato (e l'inizializzazione è mal formata se T non ha un costruttore predefinito accessibile);
- se T è un tipo di classe non sindacale senza un costruttore dichiarato dall'utente, allora ogni membro di dati non statico e componente di classe base di T è inizializzato dal valore;
- se T è un tipo di array, ogni elemento è inizializzato dal valore;
- in caso contrario, l'oggetto viene inizializzato con zero

Un programma che richiede l'inizializzazione di default o l'inizializzazione di valore di un'entità di tipo di riferimento è mal formato. Se T è un tipo con certificazione cv, la versione cv non qualificata di T viene utilizzata per queste definizioni di inizializzazione zero, inizializzazione predefinita e inizializzazione del valore.


18
Questo potrebbe non essere aggiornato per C ++ 11. cppreference.com afferma che l'inizializzazione predefinita non azzera i membri (solo l'inizializzazione del valore).
Alexei Sholik,

3
@android solleva un punto importante, che non vedo risposta altrove, quindi ho fatto una nuova domanda. stackoverflow.com/questions/22233148/…
Adrian McCarthy
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.