2013-06-20 3 views
20

Questo codice:Perché non viene fornito un costruttore di copie predefinito da un file volatile?

class X { 
    int member; 
}; 

volatile X a; 
X b = a; 

fallisce con l'errore:

prog.cpp:6:7: error: no matching function for call to ‘X::X(volatile X&)’ 
prog.cpp:6:7: note: candidates are: 
prog.cpp:1:7: note: X::X() 
prog.cpp:1:7: note: candidate expects 0 arguments, 1 provided 
prog.cpp:1:7: note: X::X(const X&) 
prog.cpp:1:7: note: no known conversion for argument 1 from ‘volatile X’ to ‘const X&’ 

C'è un modo posso ottenere il compilatore di generare un costruttore di copia volatile per me?

+0

È necessario dichiarare 'b'as' volatile'. – 0x499602D2

+0

Ma voglio una copia non volatile! – Eric

+3

'volatile X &' non può essere convertito in 'const X &' perché i due qualificatori si contraddicono a vicenda:' const' dice "leggi una volta, non cambierà", mentre 'volatile' dice" leggi ogni volta, perché può cambiare". Deve esserci una regola intelligente nello standard C++ che proibisce di effettuare questa conversione implicitamente. – dasblinkenlight

risposta

14

La risposta breve è: Perché lo standard dice che non lo farai.

Lo standard C++ 12.8/9 (Progetto N3242) dice:

The implicitly-declared copy constructor for a class X will have the form

  • X::X(const X&)

if

  • each direct or virtual base class B of X has a copy constructor whose first parameter is of type const B& or const volatile B&, and
  • for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy constructor whose first parameter is of type const M& or const volatile M&. [Note: 119]

Otherwise, the implicitly-declared copy constructor will have the form

  • X::X(X&)

Nota 119 dice:

This implies that the reference parameter of the implicitly-declared copy constructor cannot bind to a volatile lvalue; see C.1.9.

In C.1.9 troverete:

The implicitly-declared copy constructor and implicitly-declared copy assignment operator cannot make a copy of a volatile lvalue. For example, the following is valid in ISO C:

struct X { int i; }; 
volatile struct X x1 = {0}; 
struct X x2(x1); // invalid C++ 
struct X x3; 
x3 = x1; // also invalid C++ 

Rationale: Several alternatives were debated at length. Changing the parameter to volatile const X& would greatly complicate the generation of efficient code for class objects. Discussion of providing two alternative signatures for these implicitly-defined operations raised unanswered concerns about creating ambiguities and complicating the rules that specify the formation of these operators according to the bases and members.

-3

Il problema chiave è che non si fornisce il costruttore di assegnazione . Di conseguenza, il compilatore genera un predefinita per voi: costruttore di assegnazione

X& X::operator =(const X& x){ 
    this.member = x.member; 
    return *this; 
} 

L'impostazione predefinita accetta tipo di argomento come const X & in cui il const è un const basso livello vinto' t essere ignorato come const di livello superiore.

Il tuo codice X b = a significa chiamare il costruttore predefinito. Ma il vostro argomento è di tipo avolatili X (può essere convertito in volatili X & e const volatili X &) non può essere convertito in const X & implicitamente.

così si dovrebbe definire il proprio costruttore di incarico come

X& X::operator =(volatile const X&); 

EDIT
Mi sconvolge che tanti ragazzi pensano che il costruttore di copia (oppure chiama copia di inizializzazione) è chiamato quando si utilizza l'operatore di assegnazione . Forse chiamarlo l'operatore di assegnazione non è comune. Tuttavia, quello che mi interessa è quale metodo viene chiamato.

è possibile fare riferimento a questo post: Copy constructors, assignment operators, and exception safe assignment e Default assignment operator


EDIT
ho commesso un errore in precedenza. X b = a è solo un processo di inizializzazione. Nessun incarico è coinvolto Chiedere scusa per il mio messaggio di errore.

+3

No. Un costruttore come 'X (volatile const X & x): membro (x.member) {}' sarà richiesto poiché 'X b = a;' è l'inizializzazione della copia. Non esiste una cosa come "costruttore di incarichi". C'è un costruttore o un operatore di assegnazione. – Pixelchemist

+0

@Pixelchemist Ciò che fornite è chiamato "copy constructor". Questi due sono cose diverse. Si chiama ** rule of three ** in C++. – Zachary

+0

La regola del tre si applica principalmente alle classi che gestiscono le risorse. In questo caso è richiesto un costruttore di copia non esplicito per eseguire la conversione da X volatile a X. – Pixelchemist