2012-01-06 10 views
9

Scott Meyers dice:Si una excepción lanzada es siempre una copia del objeto de excepción, ¿por qué no se invoca este constructor de copia?

C++ especifica que un objeto lanzado como una excepción siempre se copia y la copia se realiza mediante la copia constructor del objeto.

Pero en mi código:

struct test 
{ 
    test() { cout << "constructor is called" << endl; } 
    test(const test&) { cout << "copy constructor is called" << endl; } 
    ~test() { cout << "destructor is called" << endl; } 
}; 

void fun() 
{ 
    throw test(); 
} 

int main() 
{ 
    try { 
     fun(); 
    } 
    catch (test& t1) { cout << "exception handler" << endl; } 
} 

no veo constructor de copia del objeto de excepción que se llama.

Si cambio el catch para recibir el objeto de excepción por valor, entonces lo es, pero según la cita de Meyers, el objeto de excepción debería haber sido copiado incluso cuando se recibió por referencia.

¿Por qué no se llama al constructor de copia (incluso cuando el manejo de excepciones se realiza por referencia)?

+2

¿Cuál es su pregunta? – cdeszaq

+5

La pregunta es "¿qué está mal: Meyers o mi compilador?" No cierre las preguntas simplemente porque no las entiende. –

Respuesta

11

Meyers es correcto que se hace una copia, semánticamente:

[C++11: 12.2/1]:Temporaries de tipo de clase son creados en varios contextos: unión a una referencia a un prvalue (8.5.3), devolviendo un prvalue (6.6.3), una conversión que crea un valor prv (4.1, 5.2.9, 5.2.11, 5.4), lanzando una excepción (15.1), ingresando un controlador (15.3), y en algunas inicializaciones (8.5). [..]

[C++11: 15.1/4]: La memoria para ser arrojado la copia temporal de la excepción se asigna de una manera no especificada, excepto como se indica en 3.7.3.1. El temporal persiste siempre que se ejecute un controlador para esa excepción.

Sin embargo, las copias pueden ser eliminadas por compiladores inteligentes y pueden hacerlo independientemente de los efectos secundarios.

[C++11: 12.8/31]:Cuando se cumplen ciertos criterios, se permite que una aplicación para omitir la construcción copiar/mover de un objeto de clase, incluso si la copia/constructor de movimiento y/o destructor del objeto tienen efectos secundarios. En tales casos, la implementación trata la fuente y el destino de la operación de copiar/mover omitida como simplemente dos formas diferentes de referirse al mismo objeto, y la destrucción de ese objeto ocurre en el momento posterior en que los dos objetos habrían sido destruido sin la optimización. Esta elisión de las operaciones de copiar/mover, llamado copia elisión, está permitido en las siguientes circunstancias (que pueden combinarse para eliminar múltiples copias):

  • [..]
  • cuando un objeto de clase temporal que no se ha vinculado a una referencia (12.2) se copiaría/movería a un objeto de clase con el mismo tipo cv no calificado, la operación copiar/mover se puede omitir construyendo el objeto temporal directamente en el destino de la copia/movimiento omitido.
  • [..]
+3

Para 12.8/31 estamos en realidad en el siguiente caso, "cuando un objeto de clase temporal que no ha sido vinculado a una referencia (12.2) sería copiado/movido a un objeto de clase con el mismo tipo cv-no calificado, la copia/la operación de movimiento puede omitirse construyendo el objeto temporal directamente en el destino de la copia/movimiento omitido ". 'test()' es el temporal, el objeto de excepción asignado de una manera no especificada es el objeto al que se está copiando/moviendo, que también pasa a ser temporal. No estamos en el caso que destacó, ya que el operando 'test()' no es el nombre de un objeto. –

+0

@SteveJessop: cierto. También creo que la condición con respecto al alcance falla debido a la "indirecta llamada de función" (término compuesto por mí). –

+0

@SteveJessop: ¿Es el caso final irrelevante debido a la aceptación por referencia? –

Cuestiones relacionadas