É seguro porque nada é criado durante a operação de troca. Somente membros de dados da classe std::vector
são trocados.
Considere o seguinte programa demonstrativo que deixa claro como os objetos da classe std::vector
são trocados.
#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;
}
A saída do programa é
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 você vê apenas membros de dados ptr
e n
é trocado na troca de função de membro. Nenhum recurso adicional é usado.
Uma abordagem semelhante é usada na classe std::vector
.
Quanto a este exemplo
std::vector<Widget> WidgetVector;
std::vector<Widget2> Widget2Vector;
depois, existem objetos de diferentes classes. A troca da função de membro é aplicada a vetores do mesmo tipo.
Sim, é perfeitamente seguro trocar vetores do mesmo tipo.
O vetor sob o capô é apenas alguns ponteiros apontando para os dados que o vetor usa e o "fim" da sequência. Quando você chama swap, basta trocar esses ponteiros entre os vetores. Você não precisa se preocupar que os vetores tenham o mesmo tamanho por causa disso.
Vetores de tipos diferentes não podem ser trocados usando
swap
. Você precisaria implementar sua própria função que faz a conversão e troca.fonte
2
. Atualizada.Sim. A troca geralmente pode ser considerada segura. Por outro lado, a segurança é subjetiva e relativa e pode ser considerada sob diferentes perspectivas. Como tal, não é possível dar uma resposta satisfatória sem aumentar a pergunta com um contexto e escolher que tipo de segurança está sendo considerada.
Não haverá UB. Sim, ainda é seguro no sentido de que o programa está mal formado.
fonte
A
swap
função é definida como se segue:void swap( T& a, T& b );
. Observe aqui que ambosa
eb
são (e devem ser) o mesmo tipo . (Não existe essa função definida com esta assinatura:void swap( T1& a, T2& b )
como não faria sentido!)Da mesma forma, a
swap()
função de membro dastd::vector
classe é definida da seguinte maneira:Agora, como não há definição 'equivalente' com uma substituição de modelo (consulte Especializações explícitas de modelos de função ) para o parâmetro de função (que seria do formato
template <typename T2> void swap(std::vector<T2>& other)
:), esse parâmetro deve ser um vetor do mesmo tipo (modelo) que a classe 'chamando' (ou seja, também deve ser avector<T1>
).Você
std::vector<Widget>
estd::vector<Widget2>
são dois tipos diferentes , portanto, a chamada paraswap
não será compilada, se você tentar usar a função de membro de qualquer objeto (como o seu código faz) ou usar a especialização dastd::swap()
função que aceita doisstd:vector
objetos como parâmetros.fonte
std::vector::swap
é uma função membro, como isso pode ser uma especialização de uma função de modelo independente ???std::swap
, não é isso que o OP está usando. Quando você o fazFirst.swap(Second);
, você chamastd::vector::swap
qual é uma função diferente destd::swap
void swap(std::vector& other)
(iestd::vector<T>
), não comotemplate <typename U> void swap(std::vector<U>& other)
(assumindo T sendo o parâmetro do tipo para o próprio vetor).Você não pode trocar vetores de dois tipos diferentes, mas é um erro de compilação em vez de UB.
vector::swap
aceita apenas vetores do mesmo tipo e alocador.Não tenho certeza se isso funcionará, mas se você deseja que um vetor contenha
Widget2
s convertido deWidget
s, tente:Widget2
terá que ser movido a partir deWidget
.fonte
using std::swap; swap(a, b);
ea.swap(b);
tem exatamente a mesma semântica em que esta funciona; pelo menos para qualquer tipo são. Todos os tipos padrão são sensatos a esse respeito.A menos que você use um alocador interessante (ou seja, com estado, nem sempre igual e não propagado na troca de contêiner, consulte
std::allocator_traits
), trocando duasstd::vector
s com os mesmos argumentos de modelo é apenas uma troca chata de três valores (capacidade, tamanho e dados) ponteiro). E trocar tipos básicos, ausência de corridas de dados, é seguro e não pode ser descartado.Isso é garantido pelo padrão. Veja
std::vector::swap()
.fonte