2011-11-21 10 views
14

In base a N2628 relativo a , gli inizializzatori di membri di dati non statici possono essere sostituiti da costruttori definiti in modo esplicito, ma sembra essere leggermente nebuloso riguardo al costruttore di copie implicitamente definito.In C++ 0x, gli inizializzatori dei membri dei dati non statici sostituiscono il costruttore implicito di copia?

In particolare, ho notato che con la versione 3.0 di Apple clang, il comportamento varia a seconda che la struct (o la classe) sia un POD.

Il seguente programma restituisce l'output "1", che indica che il costruttore di copia sta ignorando il lato destro e sostituisce invece il nuovo inizializzatore di membro dati non statici (in questo esempio, il valore vero booleano per X :: a).

#include <iostream> 
#include <string> 

struct X 
{ 
    std::string string1; 
    bool a = true; 
}; 

int main(int argc, char *argv[]) 
{ 
    X x; 
    x.a = false; 
    X y(x); 
    std::cout << y.a << std::endl; 
} 

Tuttavia, confusamente, se si commento fuori string1:

// std::string string1; 

allora il comportamento funziona come mi aspettavo (l'uscita è "0"), costruttore di copia, presumibilmente perché non c'è modo implicito generato e quindi i dati sono copiati.

La specifica C++ 0x suggerisce davvero che sia una buona idea consentire al costruttore di copie implicitamente definito di non copiare il contenuto del lato destro? Non è meno utile e non intuitivo? Trovo che la funzionalità di inizializzazione dei membri non statici sia abbastanza comoda, ma se questo è il comportamento corretto, eviterò esplicitamente la funzione a causa del suo comportamento complicato e non intuitivo.

Per favore dimmi che mi sbaglio?

UPDATE: questo errore è stato corretto nel repository di origine Clang. Vedi questo revision.

AGGIORNAMENTO: Questo bug appare corretto in Apple clang versione 3.1 (tag/Apple/clang-318.0.45) (basato su LLVM 3.1svn). Questa versione di clang è stata distribuita come parte di Xcode 4.3 per Lion.

+0

+1 per nebulosità –

risposta

10

Non è oscuro, dopo tutto, vedere parti evidenziate del standard estratto:

La sezione costruttori di copia/rinomina in default (§ 12.8) è un po 'troppo lungo citare nella sua interezza. Il basso-down è che i campi utente non statici con initializers sono ancora semplicemente copiati dal stabilizzato copia/spostamento costruttore

§ 12.8:

-6. Il costruttore di copia/spostamento implicitamente definito per una classe non unione X esegue una copia/spostamento membro delle sue basi e membri. [ Note: brace-or-equal-initializers of non-static data members are ignored. See also the example in 12.6.2. —end note ] L'ordine di inizializzazione è lo stesso dell'ordine di inizializzazione di basi e membri in un costruttore definito dall'utente (vedere 12.6.2). Sia x il parametro del costruttore o, per il costruttore di spostamenti, un valore x che si riferisce al parametro.Ogni base o non statici dati membro è copiato/spostato in modo adeguato al tipo:

  • se l'elemento è un array, ogni elemento è diretto inizializzato con il corrispondente subobject di x;
  • se un membro m ha il tipo di riferimento rvalore T & &, viene inizializzato direttamente con static_cast (x.m);
  • in caso contrario, la base o il membro viene inizializzato direttamente con la corrispondente base o membro di x.
    sottoggetti classe base virtuale va inizializzato solo una volta dal costruttore di copia/spostamento implicitamente definito

Questo è il campione di cui:

struct A { 
    int i = /* some integer expression with side effects */; 
    A(int arg) : i(arg) { } 
    // ... 
}; 

Il costruttore A (int) semplicemente inizializzerò i al valore di arg, e gli effetti collaterali nel parentesi graffa-o-equalizzatore di i non avranno luogo. —end example ]


Per completezza, la sezione corrispondente sul costruttore di default stabilizzato:

§ 12,1

-6. Un costruttore predefinito che è predefinito e non definito come eliminato è implicitamente definito quando è odr-usato (3.2) per creare un oggetto del suo tipo di classe (1.8) o quando è esplicitamente impostato dopo la sua prima dichiarazione.
Il costruttore predefinito implicitamente definito esegue l'insieme di inizializzazioni della classe che verrebbe eseguito da un costruttore predefinito scritto dall'utente per quella classe senza alcun iniziatore del test (12.6.2) e una dichiarazione composta vuota. Se quel costruttore predefinito scritto dall'utente sarebbe mal formato, il programma è mal formato.
Se tale costruttore predefinito scritto dall'utente soddisfa i requisiti di un costruttore di constexpr (7.1.5), il costruttore predefinito implicitamente definito è constexpr. Prima che il costruttore predefinito predefinito per una classe sia definito in modo implicito, tutti i costruttori predefiniti forniti dall'utente per le sue classi di base ei relativi membri di dati non statici devono essere stati definiti in modo implicito. [Nota: un costruttore predefinito implicito dichiarato ha una specifica di eccezione (15.4).
Una definizione di default esplicito potrebbe avere una specifica di eccezione implicita, vedere 8.4. —end note ]

+0

Interessante. È questo in riferimento al _copy-constructor_ predefinito? –

+0

Questo sembra riferirsi solo al costruttore predefinito, AFAIK che è il costruttore che accetta 0 argomenti. – Kleist

+0

Questo riferimento parla del costruttore * predefinito * non del costruttore * di copie * –

Problemi correlati