2009-05-05 17 views
19

C++ 11 agrega la capacidad de decirle al compilador create a default implementation de cualquiera de los special member functions. Si bien puedo ver el valor de eliminar una función, ¿dónde está el valor de predefinir explícitamente una función? Simplemente déjelo en blanco y el compilador lo hará de todos modos.¿Cuál es el punto en las funciones por defecto en C++ 11?

El único punto que puedo ver es que un constructor por defecto sólo se crea cuando no exista otra constructor:

class eg { 
public: 
    eg(int i); 
    eg() = default; 
}; 

Pero es que realmente mejor que como lo haces ahora?

class eg { 
public: 
    eg(int i); 
    eg() {} 
}; 

¿O me está faltando un maletín de uso?

Respuesta

19

Un constructor en incumplimiento tendrá una declaración, y esa declaración estará sujeta a las reglas de acceso normales. P.ej. puede hacer que el constructor de copia predeterminado esté protegido. Sin estas nuevas declaraciones, los miembros generados por defecto son públicos.

+5

[dig] Además: la definición de ciertas funciones especiales de miembro evita que el compilador falle en otras, pero puede volver a habilitarse con = default. Por ejemplo, si implementa un constructor de copia personalizado, no se generará el constructor de movimiento predeterminado. En lugar de implementarlo usted mismo, puede establecerlo explícitamente si eso fuera suficiente. – boycy

1

Sospecho que ser capaz de generar por defecto el constructor de copia será realmente útil. No puedo ver un uso para generar por defecto el constructor predeterminado, ya que como dices, la implementación que escribas sería más corta.

0

Para mí es la característica de desactivación que será útil, para la mayoría de las clases que creo deshabilitar la copia & asignación - será bueno tener una característica que el compilador pueda reconocer para hacer esto, en lugar de depender del enlazador errores

+1

Incluso ahora (C++ 98) de la que deriva de una clase non_copyable que puede tener el compilador detectar los errores (incluso cuando se utilizan en la clase misma) y que no tienen que esperar a que el momento del enlace. – Motti

+1

No creo en la introducción de la derivación para resolver problemas como este. –

16

Esos ejemplos de Stroustrup's website podrían ayudar a entender el punto:

morosos y funciones eliminadas - el control de los incumplimientos

El lenguaje común de "prohibir copiar" puede ahora expresarse directamente:

class X { 
    // ... 

    X& operator=(const X&) = delete; // Disallow copying 
    X(const X&) = delete; 
}; 

Por el contrario, también podemos decir expl icitly que queremos al comportamiento predeterminado de copia:

class Y { 
    // ... 
    Y& operator=(const Y&) = default; // default copy semantics 
    Y(const Y&) = default; 

}; 

Ser explícito sobre el valor por defecto es obviamente redundante, pero los comentarios de tal efecto y (peor) de un usuario que definen explícitamente las operaciones de copia pensados ​​para dar al defecto comportamiento son no poco común. Dejarlo en el compilador para implementar el comportamiento predeterminado es más simple, menos propenso a errores, y a menudo conduce a un mejor código de objeto. El mecanismo "predeterminado" se puede usar para cualquier función que tenga un valor predeterminado. El mecanismo "borrar" se puede usar para cualquier función con . Por ejemplo, podemos eliminar una conversión no deseada como esto:

struct Z { 
    // ... 

    Z(long long);  // can initialize with an long long 
    Z(long) = delete; // but not anything less 
}; 
+0

De hecho, hice la pregunta después de leer las preguntas más frecuentes de C++ 0x de BS, su comentario "obviamente redundante" me llevó a cuestionar todo el problema de incumplimiento. – Motti

+7

Hm ,, bummer puedes usar = eliminar en cualquier cosa pero no = por defecto. Me hubiera gustado escribir "int main() = default; // Volver a leer StackOverflow" – MSalters

12

Además de cambiar la accesibilidad (privado/protegido) de las funciones generadas, usted será capaz de hacerlos virtual.

struct S 
{ 
    virtual ~S(); 
    virtual S& operator=(const S&); 
}; 

S::~S() = default; 
S& S::operator=(const S&) = default; 

los siguientes aspectos de las funciones en mora pueden ser modificados:

    (no públicas se hagan)
  • virtuales
  • explícitas (constructores)
  • especificaciones de excepción
  • acceso
  • const-ness de los parámetros

pero para hacerlo, las funciones se deben definir fuera de la clase (8.4.2/2 en el C++0x Final Committee Draft).

Una versión de la propuesta original de Lawrence Crowl es here.

Gracias a Roger Pate para la aclaración y cita.

+0

¿Por qué gcc 4.5.0 emite el siguiente error para el código que ha publicado: 'Virtual S :: ~ S()' virtual declarado no puede ser predeterminado en el cuerpo de clase – bpw1621

+0

@bpw: Porque 8.4.2/2 (registrado en N3092) explícitamente prohíbe este código. –

+0

@Roger Gracias por la aclaración (en otro lugar). Como señaló que se requiere, he definido las funciones fuera de la clase. –

2

1) Los destructores generados implícitamente actualmente no son virtuales. Por lo tanto, debe definirlos para que sean virtuales, en cuyo caso no son tan eficientes. Con = predeterminado, tendrá destructores virtual y eficiente como generados implícitamente.

2) Tendrán especificadores de acceso, al contrario que los generados implícitamente.

3) Si alinea su constructor predeterminado, su clase seguirá siendo trivial.

Here is an article elaborating this new feature.

0

Incumplidora es más útil para la copia-constructores si tiene una clase con una gran cantidad de atributos. Por ejemplo, si usted tiene esta clase:

class MyClass { 
private: 
    int offset; 
    std::string name; 
    std::vector<Person*> relatives; 
    float weight; 
    MyClass* spouse; 
    Vehicle* car; 
    double houseArea; 
    Date birth; 
    Person* parents[2]; 

public: 
    /* Default constructor will be defined here */ 
}; 

en lugar de definir el constructor copia de la siguiente manera:

MyClass(const MyClass& that) : 
    offset(that.offset), 
    name(that.name), 
    relatives(that.relatives), 
    weight(that.weight), 
    spouse(that.spouse), 
    car(that.car), 
    houseArea(that.houseArea), 
    birth(that.birth), 
    parents(that.parents) 
{} 

debe definir de esta manera:

MyClass(const MyClass&) = default; 
+0

Sí, pero los constructores de copia predeterminados son [creados por el compilador automáticamente] (http://en.wikipedia.org/wiki/Special_member_functions) – Motti

1

Véase el Punto 17 del gran libro de Scott Meyer "Effective Modern C++". Describe muchas condiciones bajo las cuales se generan (o NO se generan) los constructores de copia predeterminados, las operaciones de copia y las operaciones de movimiento.

En otras palabras, el compilador podría no "hacerlo de todos modos". Pero si la función de miembro especial predeterminada tiene sentido, el usuario podría usar la palabra clave "predeterminada" para indicar explícitamente al compilador que genere una función predeterminada que de lo contrario no se generaría.

De las Cosas para recordar al final del artículo 17:

  • Las operaciones de movimiento sólo se generan para las clases que carecen de las operaciones de movimiento declaradas explícitamente, las operaciones de copia, o un destructor.

  • El constructor de copia se genera solo para las clases que carecen de un constructor de copia declarado explícitamente, y se elimina si se declara una operación de movimiento.El operador de asignación de copias se genera solo para las clases que carecen de un operador de asignación de copias explícitamente declarado, y se elimina si se declara una operación de movimiento. La generación de las operaciones de copia en clases con un destructor declarado explícitamente está en desuso.

Cuestiones relacionadas