2012-02-08 19 views
22

std::queue::pop() devuelve void. Por dos razones: la seguridad¿Puede queue :: pop devolver un valor ahora?

  1. excepción: algo podría lanzar después de retirar el elemento
  2. para poder return the value by reference

fina.

Ahora si entiendo la nueva semántica de movimiento de C++ 11 correctamente, la segunda ya no es un argumento válido.

Entonces ... ¿lo único que impide que std::queue tenga una función de tipo pop que devuelve el valor reside en la posibilidad de que el constructor de movimiento lance?

Me resulta difícil pensar en situaciones en las que un constructor de movimientos así lanzaría. ¿Quién sabe de un ejemplo?

supongo que lo mismo vale para std::stack::pop(), std::vector::pop_front(), std::vector::pop_back(), std::deque::pop_front(), std::deque::pop_back(), std::list::pop_front(), std::list::pop_back() y lo que no.

+0

Esas son realmente dos preguntas. Un ejemplo para un constructor de movimientos arrojadizos y un 'pop' de retorno. – pmr

+0

Necesito un ejemplo de un constructor de movimiento arrojadizo para entender por qué no podemos tener el 'pop' que regresa. –

+3

¿Qué pasa con los tipos que no tienen un constructor de movimiento en absoluto? – jalf

Respuesta

5

Utilizando técnicas SFINAE inteligentes efectivamente sería posible tener una pop_and_move no tirar atómica() por sólo tipos de datos que implementan sin tirar ningún movimiento o tirar-copia.

Incluso hay un constructo noexcept() disponible para ver si algo puede arrojar.

Uno de los nuevos conceptos en C++ 11 en particular que extiende SFINAE es que si el cuerpo no compila la función no existe. Por lo tanto, uno podría implementar basado en noexcept().

Diría que por compatibilidad con versiones anteriores la función necesitaría un nuevo nombre, que por lo tanto le permite coexistir con la funcionalidad existente de llamarlas por separado, sin romper contenedores de tipos que no tienen la semántica para permitirlo.

+0

¿Podría explicar la extensión de SFINAE en C++ 11 (una referencia estándar sería agradable)? No he oído nada de eso y me gustaría leer más. – Grizzly

+1

Fue mencionado por Alexandrescu en su charla sobre plantillas variadas en la conferencia Going Native. Como parte del principio de "falla de sustitución no es un error", si el cuerpo no compila esto se considera una falla de sustitución también (por lo tanto, ignore esta especialización). Con noexcept() probablemente ya sea posible crear una función que usaría mover si está disponible y no tirar, luego usaría copiar como segunda opción si está disponible y no lanzar, y no compilará lo contrario. – CashCow

+1

¡Suena prometedor! Esta respuesta no es la respuesta más directa a mis preguntas, pero en realidad es lo que estaba buscando sin saber. –

6

No hay muchos casos en que std::move() pueda arrojar en la biblioteca estándar, pero hay casos. Por ejemplo, si el contenedor usa un asignador con estado, sus hijos también usan este asignador, pero no se moverá a un resultado: esto preferiría obtener una versión construida predeterminada de un asignador (si lo eliminé correctamente). Dado que los asignadores son con estado, esto significa que el objeto no se puede mover y, por lo tanto, la construcción del movimiento falla con una excepción. ¿Por qué este tipo tiene un constructor de movimiento? Bueno, porque podría crearse una instancia con un asignador no con estado, en cuyo caso el movimiento no arrojaría. Además, una vez que nos movemos a las clases definidas por el usuario, no tenemos idea de bajo qué condición podría moverlas.

+0

Terminas haciendo tantas preguntas con un giro interesante. Algún día, cuando tenga tiempo, revisaré tu perfil y leeré todas tus respuestas para todo. – odinthenerd

1

Otro problema es que no todas las clases realmente se benefician del movimiento, es decir, que solo pueden tener un copiador.

struct DontLikeMoves{ 
    // some data, whatever... 
    DontLikeMoves(DontLikeMoves const& other){ 
    // might throw, who knows! 
    // and this will even get called for rvalues 
    } 
}; 
Cuestiones relacionadas