9

consideri il codice qui sottoVS2013 inizializzazione di default vs inizializzazione valore

struct B 
{ 
    B() : member{}{}; 
    int member[10]; 
}; 

int main() 
{ 
    B b; 
} 

VS2013 compilatore dà il seguente avviso:

avvertimento C4351: nuovo comportamento: gli elementi della serie 'B :: membro' saranno predefinito inizializzata 1> test.vcxproj -> C: \ Users \ asaxena2 \ documenti \ visual Studio 2013 Projects \ test \ Debug \ test.exe \

Questo è documentato here

Con C++ 11, e applicando il concetto di 'inizializzazione predefinita', significa che gli elementi di B.member non verranno inizializzate.

Ma credo che member{} debba eseguire l'inizializzazione del valore e non l'inizializzazione predefinita. Il compilatore VS2013 è rotto?

$ 8,5/6

Per default-inizializzare un oggetto di tipo T significa: - se T è un (possibilmente cv-qualificato) tipo di classe (Clausola 9), è chiamato il costruttore predefinito per T (e l'inizializzazione è mal formata se T non ha un costruttore predefinito accessibile);
- se T è un tipo di matrice, ogni elemento viene inizializzato automaticamente;
- in caso contrario, non viene eseguita alcuna inizializzazione.
Se un programma richiede l'inizializzazione predefinita di un oggetto di tipo const -qualificato T, T deve essere un tipo di classe con un costruttore predefinito fornito dall'utente.

$ 8.5.1

List-inizializzazione di un oggetto o di riferimento di tipo T è definito come segue:
- Se la lista di inizializzazione non ha elementi e T è un tipo di classe con un default costruttore, l'oggetto è inizializzato a valore.
- Altrimenti, se T è un aggregato, viene eseguita l'inizializzazione di aggregazione (8.5.1).

Se nella lista ci sono meno clausole di inizializzatore di quante ne siano membri nell'aggregato, allora ciascun membro non inizializzato esplicitamente deve essere inizializzato da un elenco di inizializzazione vuoto (8.5.4). [Esempio:

struct S { int a; const char* b; int c; }; 
    S ss = { 1, "asdf" }; 

inizializza ss.a con 1, ss.b con "asdf", e ss.c con il valore di un'espressione della forma int(), cioè, 0.esempio -end]

+0

Questa è una buona domanda, ma "comportamento del compilatore di Visual Studio" è un titolo orribile. Considera di cambiarlo in qualcosa di più significativo. Detto questo, hai verificato il comportamento del compilatore? Potrebbe benissimo essere un avvertimento fuorviante. – hvd

+0

@hvd: cambiato. Grazie – user3701522

risposta

7

Sembra essere un messaggio di avviso in modo non corretto formulato (e sono sorpreso che sta stampando un avvertimento in primo luogo), ma il comportamento è corretto . B::member viene inizializzato in base al valore, che per un array di int diventa zero inizializzazione. Questo può essere dimostrato mediante la seguente:

#include <iostream> 

struct B 
{ 
    B() : member{}{}; 
    int member[10]; 
}; 

struct C 
{ 
    C() {}; 
    int member[10]; 
}; 

int main() 
{ 
    B b; 
    for(auto const& a : b.member) std::cout << a << ' '; 
    std::cout << std::endl; 

    C c; 
    for(auto const& a : c.member) std::cout << a << ' '; 
    std::cout << std::endl; 
} 

Se compilate ed eseguite in Debug modalità questo si traduce in uscita:

0 0 0 0 0 0 0 0 0 0 
-858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 

I numeri della seconda linea sono 0xCCCCCCCC, il modello di debug il compilatore VC++ riempie la memoria con in modalità Debug. Pertanto, B::member viene inizializzato a zero, mentre non viene eseguita alcuna inizializzazione per C::member.

Diniego: So che la lettura da una variabile non inizializzata è un comportamento indefinito, ma questo è il migliore prova ho potuto trovare.

+1

Ho anche controllato lo smontaggio e vedo la chiamata a memset per valori più grandi della dimensione della variabile membro. Quindi, c'è una chiamata esplicita a memset che significa che è zero inizializzazione come richiesto dallo standard. Per valori più piccoli di n è l'ottimizzazione e l'impostazione di 0 in un modo diverso (elemento per elemento) – user3701522

2

L'avviso del compilatore non è corretto; in realtà sta eseguendo l'inizializzazione del valore come richiesto dallo standard.

Esempio:

#include <iostream> 

struct B { 
    B() : member{}{}; 
    int member[10]; 
}; 

int main() { 
    int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 
    B &b = *new (a) B; 
    std::cout << b.member[9]; // prints '0' 
} 
0

Il MSDN page dice:

C4351 significa che si dovrebbe ispezionare il codice ... Se si desidera che il nuovo comportamento, che è probabile, perché la matrice era esplicitamente aggiunto a nell'elenco di inizializzazione dei membri del costruttore, utilizzare il pragma per disabilitare l'avviso. Il nuovo comportamento dovrebbe andare bene per la maggior parte degli utenti di .

Quindi è necessario aggiungere #pragma warning (suppress:4351) per una riga o #pragma warning (disable:4351) per l'intero file.

Problemi correlati