2011-05-28 6 views
21

En N3059 encontré la descripción de por partes construcción de pares (y tuplas) (y está en la nueva Norma).C++ 11 use-case para piecewise_construct de par y tupla?

Pero no puedo ver cuándo debería usarlo. Encontré discusiones sobre emplace y entidades que no se pueden copiar, pero cuando lo probé, no pude crear un caso en el que I necesitepiecewiese_construct o podría ver un beneficio en el rendimiento.

Ejemplo. Pensé que necesito una clase que es no copiable, pero movebale (necesario para el avance):

struct NoCopy { 
    NoCopy(int, int) {}; 
    NoCopy(const NoCopy&) = delete; // no copy 
    NoCopy& operator=(const NoCopy&) = delete; // no assign 
    NoCopy(NoCopy&&) {}; // please move 
    NoCopy& operator=(NoCopy&&) {}; // please move-assign 
}; 

Entonces tipo de esperaba ese par-construcción estándar fallaría:

pair<NoCopy,NoCopy> x{ NoCopy{1,2}, NoCopy{2,3} }; // fine! 

pero no fue así. En realidad, esto es lo que esperaba de todos modos, porque "moviendo cosas" en lugar de copiarlo a todas partes en el archivo stdlib, debería ser.

Por lo tanto, no veo ninguna razón por la que debería haber hecho esto, más o menos:

pair<NoCopy,NoCopy> y(
    piecewise_construct, 
    forward_as_tuple(1,2), 
    forward_as_tuple(2,3) 
); // also fine 
  • Por lo tanto, lo que es un caso de uso del ?
  • ¿Cómo y cuándo uso piecewise_construct?
+0

Pruebe también deshabilitar el constructor movimiento. –

Respuesta

28

No todos los tipos se pueden mover con más eficacia que los copiados, y para algunos tipos puede tener sentido incluso deshabilitar explícitamente tanto la copia como el movimiento. Considere std::array<int, BIGNUM> como un ejemplo del tipo anterior de un tipo.

el punto con la emplace funciones y piecewise_construct es que una clase de este tipo puede ser construido en lugar, sin necesidad de crear instancias temporales para mover o copiar.

struct big { 
    int data[100]; 
    big(int first, int second) : data{first, second} { 
     // the rest of the array is presumably filled somehow as well 
    } 
}; 

std::pair<big, big> pair(piecewise_construct, {1,2}, {3,4}); 

Comparar lo anterior a pair(big(1,2), big(3,4))big donde dos objetos temporales tendrían que ser creado y luego se copia - y en movimiento no ayuda aquí en absoluto! Del mismo modo:

std::vector<big> vec; 
vec.emplace_back(1,2); 

El caso de uso principal para trozos construcción de un par se emplazar elementos en un map o un unordered_map:

std::map<int, big> map; 
map.emplace(std::piecewise_construct, /*key*/1, /*value*/{2,3}); 
+1

Lo describiste muy bien, gracias. Y eso es todo lo que yo pensaba, también. Pero 'pair (piecewise_construct, ...)' no funciona si ** inhabilita el movimiento en la clase de destino ** (con '= delete'). Lo probé con gcc-4.7.0 y * obtuve un error de compilación *. razón: implementación de 'pair':
' template pair (piecewise_construct_t, tupla <_Args1...> __primera, tupla <_Args2...> __segundo): primero (__ cons (std :: mover (__primero))), segundo (__cons (std :: mover (__ segundo))) {} 'Como puedas ver, se requiere un ** movimiento **. ** emplace ** no parece ser usado. – towi

+0

Ok, parece que gcc-4.7.0 aún no ofrece 'map.emplace()'. Pero esto todavía deja mi pregunta sobre el 'pair (piecewise_construct, {...}, {...})'. ¿Debería funcionar esto con los objetos * no copiables * ** y ** * no móviles *? De la formulación en Std 20.3.2. (14) podría parecer de esa manera. Aunque se menciona "reenvío", parece aplicarse a los argumentos de los constructores y no a los objetos en sí (¿dónde podría ser necesario un movimiento?). – towi

+0

@towi: Creo que gcc-4.7.0 + libstdC++ aún no es compatible con el constructor de pares con piecewise_construct. Los objetos no copiables y no movibles deberían funcionar y, por ejemplo, clang + libC++ da el resultado correcto. @JohannesD: No entiendo por qué crees que map.emplace debería funcionar con piecewise_construct? Cada propuesta de la que soy consciente parece implicar que el uso de emplace debería ser 'map.emplace (Key, ArgForValue ...)', por ejemplo 'map.emplace (/ * key */1,/* value */2, 3); '(y así es como se comporta clang + libC++) –