Il est sûr car rien n'est créé pendant l'opération de swap. Seuls les membres de données de la classe std::vector
sont échangés.
Considérez le programme de démonstration suivant qui indique clairement comment les objets de la classe std::vector
sont échangés.
#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 sortie du programme est
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
Comme vous ne voyez que les membres de données ptr
et n
sont échangés dans l'échange de fonction membre. Aucune ressource supplémentaire n'est utilisée.
Une approche similaire est utilisée dans la classe std::vector
.
Quant à cet exemple
std::vector<Widget> WidgetVector;
std::vector<Widget2> Widget2Vector;
puis il y a des objets de différentes classes. L'échange de fonction membre est appliqué aux vecteurs du même type.
Oui, il est parfaitement sûr d'échanger des vecteurs du même type.
Le vecteur sous le capot n'est que quelques pointeurs pointant vers les données utilisées par le vecteur et la "fin" de la séquence. Lorsque vous appelez swap, vous échangez simplement ces pointeurs entre les vecteurs. Vous n'avez pas à vous inquiéter du fait que les vecteurs sont de la même taille à cause de cela.
Les vecteurs de types différents ne peuvent pas être échangés à l'aide de
swap
. Vous devez implémenter votre propre fonction qui effectue la conversion et l'échange.la source
2
. Mise à jour.Oui. L'échange peut généralement être considéré comme sûr. D'un autre côté, la sécurité est subjective et relative et peut être considérée sous différents angles. En tant que tel, il n'est pas possible de donner une réponse satisfaisante sans augmenter la question avec un contexte et sans choisir le type de sécurité envisagé.
Il n'y aura pas d'UB. Oui, il est toujours sûr dans le sens où le programme est mal formé.
la source
La
swap
fonction est définie comme suit:void swap( T& a, T& b );
. Notez ici que les deuxa
etb
sont (et doivent être) du même type . (Il n'y a pas une telle fonction définie avec cette signature:,void swap( T1& a, T2& b )
car cela n'aurait aucun sens!)De même, la
swap()
fonction membre de lastd::vector
classe est définie comme suit:Maintenant, comme il n'y a pas de définition «équivalente» avec un remplacement de modèle (voir Spécialisations explicites de modèles de fonction ) pour le paramètre de fonction (qui serait de la forme:)
template <typename T2> void swap(std::vector<T2>& other)
, ce paramètre doit être un vecteur du même type (modèle) que la classe «appelante» (c'est-à-dire qu'elle doit également être avector<T1>
).Votre
std::vector<Widget>
etstd::vector<Widget2>
sont deux types différents , donc l'appel àswap
ne sera pas compilé, que vous essayiez d'utiliser la fonction membre de l'un ou l'autre objet (comme le fait votre code), ou que vous utilisiez la spécialisation de lastd::swap()
fonction qui prend deuxstd:vector
objets comme paramètres.la source
std::vector::swap
est une fonction membre, comment cela peut-il être une spécialisation d'une fonction de modèle autonome ???std::swap
, ce n'est pas ce que l'OP utilise. Lorsque vous le faitesFirst.swap(Second);
, vous appelezstd::vector::swap
ce qui est une fonction différente destd::swap
void swap(std::vector& other)
(c'est-à-direstd::vector<T>
), pas commetemplate <typename U> void swap(std::vector<U>& other)
(en supposant que T soit le paramètre de type pour le vecteur lui-même).Vous ne pouvez pas échanger des vecteurs de deux types différents mais c'est une erreur de compilation au lieu de UB.
vector::swap
accepte uniquement les vecteurs du même type et allocateur.Je ne sais pas si cela fonctionnera, mais si vous voulez un vecteur contenant
Widget2
s converti à partir deWidget
s, vous pouvez essayer ceci:Widget2
devra être déplacer constructible deWidget
.la source
using std::swap; swap(a, b);
eta.swap(b);
ont exactement la même sémantique où celle-ci fonctionne; au moins pour tout type sain d'esprit. Tous les types standard sont sains à cet égard.Sauf si vous utilisez un allocateur intéressant (c'est-à-dire avec état, pas toujours égal et non propagé sur l'échange de conteneurs, voir
std::allocator_traits
), l'échange de deuxstd::vector
s avec les mêmes arguments de modèle n'est qu'un échange ennuyeux de trois valeurs (pour la capacité, la taille et les données) aiguille). Et l'échange de types de base, les courses de données absentes, est sûr et ne peut pas être lancé.Cela est même garanti par la norme. Tu vois
std::vector::swap()
.la source