2011-11-21 12 views
14

Según N2628 relacionado con , los inicializadores de miembros de datos no estáticos pueden anularse mediante constructores definidos explícitamente, pero parece ser ligeramente nebuloso con respecto al constructor de copia definido implícitamente.En C++ 0x, ¿los inicializadores de miembros de datos no estáticos anulan el constructor de copia implícito?

En particular, he notado que con Apple clang versión 3.0, el comportamiento varía dependiendo de si la estructura (o clase) es un POD.

El siguiente programa devuelve la salida "1", que indica que el constructor de copias ignora el lado derecho y sustituye el nuevo inicializador de miembros de datos no estáticos (en este ejemplo, el valor booleano verdadero para 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; 
} 

Sin embargo, confusamente, si comentar cabo cadena1:

// std::string string1; 

trabaja entonces el comportamiento como esperaba (la salida es "0"), es de suponer que no, porque no se genera de forma implícita al constructor de copia y, por lo tanto, los datos son copiados.

¿La especificación C++ 0x realmente sugiere que es una buena idea permitir que el constructor de copias definido implícitamente no copie el contenido del lado derecho? ¿No es menos útil y poco intuitivo? Encuentro que la funcionalidad del inicializador de miembros no estáticos es bastante conveniente, pero si este es el comportamiento correcto, entonces evitaré explícitamente la función debido a su comportamiento engañoso y poco intuitivo.

Por favor, dime que estoy equivocado?

ACTUALIZACIÓN: Este error se ha solucionado en el repositorio fuente de Clang. Vea esto revision.

ACTUALIZACIÓN: Este error aparece fijo en Apple clang versión 3.1 (etiquetas/Apple/clang-318.0.45) (basado en LLVM 3.1svn). Esta versión de clang se distribuyó como parte de Xcode 4.3 para Lion.

+0

+1 for nebulosity –

Respuesta

10

No es sombría, después de todo, ver partes resaltadas del extracto estándares:

El apartado de constructores de copiar/mover en default (§ 12.8) es un poco demasiado largo citar en su totalidad. La baja hacia abajo es que los campos miembros no estáticos con inicializadores están siendo simplemente se copian por el default copiar/mover constructor

§ 12.8:

-6. El constructor de copiar/mover implícitamente definido para una clase X no sindicalizada realiza una copia/movimiento de miembro de sus bases y miembros. [ Note: brace-or-equal-initializers of non-static data members are ignored. See also the example in 12.6.2. —end note ] El orden de inicialización es el mismo que el de la inicialización de bases y miembros en un constructor definido por el usuario (consulte 12.6.2). Sea x el parámetro del constructor o, para el constructor de movimientos, un valor x referente al parámetro.Cada base de datos o no estáticos miembro se ha copiado/movido en la manera apropiada a su tipo:

  • si el miembro es una matriz, cada elemento es directa inicializado con el subobjeto correspondiente de x;
  • si un miembro m tiene el tipo de referencia rvalue T & &, está inicializado directamente con static_cast (x.m);
  • de lo contrario, la base o miembro se inicializa directamente con la base o miembro correspondiente de x.
    subobjetos clase base virtual se inicializan sólo una vez por el constructor de copia/movimiento definido implícitamente-

Esta es la muestra se refiere a:

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

El Un constructor (int) simplemente inicializará i con el valor de arg, y los efectos secundarios en el inicializador de corchetes o igualadores de i no se llevarán a cabo. —end example ]


Para completar, la sección correspondiente en el constructor predeterminado omitido:

§ 12,1

-6. Un constructor predeterminado que se defecto y no se define como eliminado se define implícitamente cuando es ODR-utilizado (3.2) para crear un objeto de su tipo de clase (1.8) o cuando se predetermina de forma explícita después de su primera declaración.
El constructor predeterminado implícitamente definido realiza el conjunto de inicializaciones de la clase que realizaría un constructor predeterminado escrito por el usuario para esa clase sin inicializador de ctor (12.6.2) y una sentencia compuesta vacía. Si el constructor predeterminado escrito por el usuario estuviera mal formado, el programa está mal formado.
Si el constructor predeterminado escrito por el usuario satisface los requisitos de un constructor constexpr (7.1.5), , el constructor predeterminado implícitamente definido es constexpr. Antes de que se defina implícitamente el constructor predeterminado predeterminado para una clase , todos los constructores predeterminados no provistos por el usuario para sus clases base y sus miembros de datos se habrán definido implícitamente. [Nota: Un constructor predeterminado implícitamente declarado tiene una especificación de excepción (15.4).
Una definición explícitamente predeterminada puede tener una especificación de excepción implícita, ver 8.4. —end note ]

+0

Interesante. ¿Esto es en referencia al predeterminado _copy-constructor_? –

+0

Esto parece referirse solo al constructor predeterminado, AFAIK que es el constructor que toma 0 argumentos. – Kleist

+0

conversaciones de esta referencia sobre el constructor por defecto * * * no es el constructor de copia * –

Cuestiones relacionadas