2012-11-15 9 views
10

Guardate il seguente codice:In che modo il costruttore di movimento sintetizzato C++ è interessato da membri volatili e virtuali?

struct node 
{ 

    node(); 
    //node(const node&); //#1 
    //node(node&&);   //#2 

    virtual     //#3 
    ~node(); 

    node* 
    volatile    //#4 
    next; 

}; 

int main() 
{ 

    node m(node());   //#5 
    node n=node();   //#6 
} 

Quando compilato con gcc-4.6.1 che produce il seguente errore:

g++ -g --std=c++0x -c -o node.o node.cc 
node.cc: In constructor node::node(node&&): 
node.cc:3:8: error: expression node::next has side-effects 
node.cc: In function int main(): 
node.cc:18:14: note: synthesized method node::node(node&&) first required here 

Mi pare di capire che il compilatore non riesce a creare movimento predefinito o costruttore di copia su linea # 6, se disapprovo o la riga n. 1 o n. 2 compila bene, è chiaro. Il codice viene compilato correttamente senza l'opzione C++ 0x, quindi l'errore è correlato al costruttore di mosse predefinito.

Tuttavia, che cosa nella classe nodo impedisce la creazione del costruttore di spostamento predefinito? Se commento qualcuna delle righe # 3 o # 4 (cioè rende il distruttore non virtuale o rende non-volatile il membro dei dati), ricompila, quindi è la combinazione di questi due che non lo fa compilare?

Un altro enigma, la riga n. 5 non causa un errore di compilazione, cosa c'è di diverso dalla riga n. È tutto specifico per gcc? o gcc-4.6.1?

+1

Hai dimenticato il tipo di ritorno di 'main' là skippy –

risposta

12

[C++11: 12.8/9]:If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

  • X does not have a user-declared copy constructor,
  • X does not have a user-declared copy assignment operator,
  • X does not have a user-declared move assignment operator,
  • X does not have a user-declared destructor, and
  • the move constructor would not be implicitly defined as deleted.

[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. —end note ]

Ecco perché il tuo n. 3 sta rompendo la sintesi.

Inoltre, it's far from clear che volatile types (including your node* volatile) are trivially copyable; si potrebbe concludere che it is implementation-defined whether they are or not e, nel tuo caso, sembra che non lo siano.

Per lo meno, GCC made it stop working quite deliberately in v4.7, con la proposta di un backport in v4.6.1 che posso solo presumo andato avanti ...

Quindi, data la seguente:

[C++11: 12.8/11]: An implicitly-declared copy/move constructor is an inline public member of its class. A defaulted copy/move constructor for a class X is defined as deleted (8.4.3) if X has:

  • a variant member with a non-trivial corresponding constructor and X is a union-like class, a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M ’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,
  • a direct or virtual base class B that cannot be copied/moved because overload resolution (13.3), as applied to B ’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,
  • any direct or virtual base class or non-static data member of a type with a destructor that is deleted or inaccessible from the defaulted constructor,
  • for the copy constructor, a non-static data member of rvalue reference type, or
  • for the move constructor, a non-static data member or direct or virtual base class with a type that does not have a move constructor and is not trivially copyable.

... ecco perché il tuo # 4 sta anche rompendo la sintesi, indipendentemente dalla # 3.

Quanto a 5 #, che non è in realtà una dichiarazione di un node a tutti, ma una dichiarazione di una funzione chiamata m — è per questo che non è riprodurre i sintomi legati alla costruzione di un node (questo è noto come il Most Vexing Parse) .

+0

Grazie, hai reso molto chiaro. Quello che mi infastidisce ancora, è che questo codice funziona bene: – user1827766

+0

Ciò che ancora mi lascia perplesso, è che questo codice funziona bene: struct node {~ node(); nodo * volatile successivo; }; e anche questo: struct node {virtual ~ node(); nodo * successivo; }; quindi gcc-4.6.1 consente ai vettori di muovere i membri di dati volatili e alle classi con distruttori ma in qualche modo lamenta sulla combinazione di membri virtuali di dati dtor/volatile. – user1827766

+0

Mi chiedo se il problema con volatile di essere banalmente riproducibile sia solo la semantica atomica che alcune implementazioni vogliono dargli. Se è così, mi sembra che quel cambiamento non sarebbe appropriato, perché in ISO C++ volatile non ha semantica atomica – bames53