Es seguro porque no se crea nada durante la operación de intercambio. Solo std::vector
se intercambian los miembros de datos de la clase .
Considere el siguiente programa demostrativo que deja en claro cómo std::vector
se intercambian los objetos de la clase .
#include <iostream>
#include <utility>
#include <iterator>
#include <algorithm>
#include <numeric>
class A
{
public:
explicit A( size_t n ) : ptr( new int[n]() ), n( n )
{
std::iota( ptr, ptr + n, 0 );
}
~A()
{
delete []ptr;
}
void swap( A & a ) noexcept
{
std::swap( ptr, a.ptr );
std::swap( n, a.n );
}
friend std::ostream & operator <<( std::ostream &os, const A &a )
{
std::copy( a.ptr, a.ptr + a.n, std::ostream_iterator<int>( os, " " ) );
return os;
}
private:
int *ptr;
size_t n;
};
int main()
{
A a1( 10 );
A a2( 5 );
std::cout << a1 << '\n';
std::cout << a2 << '\n';
std::cout << '\n';
a1.swap( a2 );
std::cout << a1 << '\n';
std::cout << a2 << '\n';
std::cout << '\n';
return 0;
}
La salida del programa es
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4 5 6 7 8 9
Como ve solo los miembros de datos ptr
y n
se intercambian en el intercambio de funciones miembro. No se utilizan recursos adicionales.
Un enfoque similar se utiliza en la clase std::vector
.
En cuanto a este ejemplo
std::vector<Widget> WidgetVector;
std::vector<Widget2> Widget2Vector;
entonces hay objetos de diferentes clases. El intercambio de funciones miembro se aplica a vectores del mismo tipo.
Sí, esto es perfectamente seguro para intercambiar vectores del mismo tipo.
El vector debajo del capó son solo algunos indicadores que apuntan a los datos que usa el vector y al "final" de la secuencia. Cuando llamas a swap solo intercambias esos punteros entre los vectores. No necesita preocuparse de que los vectores sean del mismo tamaño debido a esto.
Los vectores de diferentes tipos no se pueden intercambiar usando
swap
. Tendría que implementar su propia función que realiza la conversión y el intercambio.fuente
2
. Actualizado.Si. El intercambio generalmente se puede considerar seguro. Por otro lado, la seguridad es subjetiva y relativa y puede considerarse desde diferentes perspectivas. Como tal, no es posible dar una respuesta satisfactoria sin aumentar la pregunta con un contexto y elegir qué tipo de seguridad se está considerando.
No habrá UB. Sí, todavía es seguro en el sentido de que el programa está mal formado.
fuente
La
swap
función se define como sigue:void swap( T& a, T& b );
. Tenga en cuenta aquí que ambosa
yb
son (y tienen que ser) del mismo tipo . (No existe tal función definida con esta firma: ¡void swap( T1& a, T2& b )
ya que no tendría sentido!)Del mismo modo, la
swap()
función miembro de lastd::vector
clase se define de la siguiente manera:Ahora, como no existe una definición 'equivalente' con una anulación de plantilla (consulte Especializaciones explícitas de plantillas de función ) para el parámetro de función (que sería de la forma:)
template <typename T2> void swap(std::vector<T2>& other)
, ese parámetro debe ser un vector del mismo tipo (plantilla) que la clase 'llamante' (es decir, también debe ser avector<T1>
).Tu
std::vector<Widget>
ystd::vector<Widget2>
son dos tipos diferentes , por lo que la llamada aswap
no se compilará, ya sea que intentes usar la función miembro de cualquiera de los objetos (como lo hace tu código) o usar la especialización de lastd::swap()
función que toma dosstd:vector
objetos como parámetros.fuente
std::vector::swap
es una función miembro, ¿cómo puede ser eso una especialización de una función de plantilla independiente?std::swap
, eso no es lo que está utilizando el OP. Cuando lo hacesFirst.swap(Second);
, llamas,std::vector::swap
que es una función diferente destd::swap
void swap(std::vector& other)
(es decirstd::vector<T>
), no comotemplate <typename U> void swap(std::vector<U>& other)
(suponiendo que T sea un parámetro de tipo para el vector mismo).No puede intercambiar vectores de dos tipos diferentes, pero es un error de compilación en lugar de UB.
vector::swap
solo acepta vectores del mismo tipo y asignador.No estoy seguro de si esto funcionará, pero si desea un vector que contenga
Widget2
s convertido deWidget
s, puede intentar esto:Widget2
tendrá que ser movible desdeWidget
.fuente
using std::swap; swap(a, b);
ya.swap(b);
tienen exactamente la misma semántica donde trabaja este último; al menos para cualquier tipo sano. Todos los tipos estándar son sanos en ese sentido.A menos que use un asignador interesante (es decir, con estado, no siempre igual y no propagado en el intercambio de contenedores, ver
std::allocator_traits
), intercambiar dosstd::vector
s con los mismos argumentos de plantilla es solo un intercambio aburrido de tres valores (para capacidad, tamaño y datos) puntero). Y el intercambio de tipos básicos, carreras de datos ausentes, es seguro y no se puede lanzar.Eso incluso está garantizado por el estándar. Ver
std::vector::swap()
.fuente