tuple pairs make_pair example ejemplo c++ c++11 move-semantics std-pair move-constructor

make_pair - vector of pairs c++



Usando la semántica de movimiento con std:: pair o std:: tuple (2)

Supongamos que desea aprovechar la semántica de movimientos, pero una de sus clases móviles debe ser parte de un std::pair . El propósito sería crear una función que devuelva un std::pair que pueda tratarse como un valor de r, y reenviarse.

Pero no puedo ver cómo se puede hacer esto, a menos que se realice un cambio interno a std::pair , para que esté al tanto de la semántica de movimientos.

Considere el siguiente código:

struct Foo { Foo() { } Foo(Foo&& f) { } private: Foo(const Foo& f) { } // do not allow copying }; int main() { Foo f; std::pair<Foo, int> res = std::make_pair(f, 10); // fails due to private copy constructor }

El problema es que std::make_pair , así como el propio constructor std::pair , toma dos objetos e intenta hacer copias internas de ellos. Esto hace que intente e invoque al constructor de copia. Pero en mi ejemplo, quiero poder mover el nuevo par a la res y asegurar que no se hagan copias. Pensaría que esto no sería posible a menos que std::pair tuviera el siguiente constructor definido internamente:

pair(T1&& t1, T2&& t2) : first(std::move(t1)), second(std::move(t2))

Pero no es así, al menos no en el compilador que estoy usando (gcc 4.3.2). Puede ser que mi compilador esté simplemente desactualizado y, de hecho, las versiones más recientes tengan este constructor que tenga en cuenta los movimientos. Pero mi comprensión de la semántica de movimientos es algo inestable en este momento, así que no estoy seguro de si simplemente estoy pasando por alto algo aquí. Entonces, ¿es posible lo que estoy tratando de lograr, sin volver a implementar std::pair ? ¿O es que mi compilador está desactualizado?


GCC 4.3.2 no debe tener una implementación completa. La pareja (y la tupla) deberán tener constructores de movimiento:

template<class U, class V> pair(U&& x, V&& y);

Efectos: el constructor inicializa primero con std :: forward (x) y segundo con std :: forward (y).

template<class U, class V> pair(pair<U, V>&& p);

Efectos: el constructor inicializa primero con std :: move (p.first) y segundo con std :: move (p.second).

(De [pairs.pair] en n3126)


Sin embargo, ese no es el constructor std::pair que se llamará. Se llamará al constructor de movimiento std::pair , y el constructor de movimiento debe hacer exactamente lo que espera (N3126 20.3.5.2/6):

template<class U, class V> pair(pair<U, V>&& p);

Efectos: el constructor inicializa primero con std::move(p.first) y segundo con std::move(p.second) .

Sin embargo, su ejemplo debería fallar porque en std::make_pair(f, 10); , f es un valor límico y debe move explícitamente d, de lo contrario se copia. Lo siguiente debería funcionar:

std::pair<Foo, int> res = std::make_pair(std::move(f), 10);