Es ist sicher, da während des Swap-Vorgangs nichts erstellt wird. Es werden nur Datenelemente der Klasse std::vector
ausgetauscht.
Betrachten Sie das folgende Demonstrationsprogramm, das deutlich macht, wie Objekte der Klasse std::vector
ausgetauscht werden.
#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;
}
Die Programmausgabe ist
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
Wie Sie sehen, werden nur Datenelemente ptr
und n
in der Elementfunktion ausgetauscht. Es werden keine zusätzlichen Ressourcen verwendet.
Ein ähnlicher Ansatz wird in der Klasse verwendet std::vector
.
Wie für dieses Beispiel
std::vector<Widget> WidgetVector;
std::vector<Widget2> Widget2Vector;
dann gibt es Objekte verschiedener Klassen. Der Elementfunktionsaustausch wird auf Vektoren des gleichen Typs angewendet.
Ja, dies ist absolut sicher, um Vektoren des gleichen Typs auszutauschen.
Der Vektor unter der Haube ist nur ein paar Zeiger, die auf die vom Vektor verwendeten Daten und das "Ende" der Sequenz verweisen. Wenn Sie Swap aufrufen, tauschen Sie einfach diese Zeiger zwischen den Vektoren aus. Sie müssen sich deshalb keine Sorgen machen, dass die Vektoren dieselbe Größe haben.
Vektoren unterschiedlicher Typen können nicht mit ausgetauscht werden
swap
. Sie müssten Ihre eigene Funktion implementieren, die die Konvertierung und den Austausch vornimmt.quelle
2
. Aktualisiert.Ja. Das Tauschen kann allgemein als sicher angesehen werden. Andererseits ist Sicherheit subjektiv und relativ und kann aus verschiedenen Perspektiven betrachtet werden. Daher ist es nicht möglich, eine zufriedenstellende Antwort zu geben, ohne die Frage mit einem Kontext zu ergänzen und zu entscheiden, welche Art von Sicherheit in Betracht gezogen wird.
Es wird keine UB geben. Ja, es ist immer noch sicher in dem Sinne, dass das Programm schlecht geformt ist.
quelle
Die
swap
Funktion ist wie folgt definiert :void swap( T& a, T& b );
. Beachten Sie hier, dass beidea
und vom selben Typb
sind (und sein müssen) . (Mit dieser Signatur ist keine solche Funktion definiert : , da dies keinen Sinn ergeben würde!)void swap( T1& a, T2& b )
In ähnlicher Weise ist die
swap()
Elementfunktion derstd::vector
Klasse wie folgt definiert:Da es für den Funktionsparameter (der die Form :) hat, keine 'äquivalente' Definition mit einer Vorlagenüberschreibung gibt (siehe Explizite Spezialisierungen von Funktionsvorlagen
template <typename T2> void swap(std::vector<T2>& other)
), muss dieser Parameter ein Vektor desselben Typs (Vorlage) sein wie die 'rufende' Klasse (das heißt, es muss auch eine seinvector<T1>
).Sie
std::vector<Widget>
undstd::vector<Widget2>
sind zwei verschiedene Typen, sodass der Aufruf vonswap
nicht kompiliert wird, unabhängig davon, ob Sie versuchen, die Elementfunktion eines Objekts (wie Ihr Code) oder die Spezialisierung derstd::swap()
Funktion zu verwenden, die zwei benötigtstd:vector
Objekte als Parameter verwendet.quelle
std::vector::swap
ist eine Mitgliedsfunktion, wie kann das eine Spezialisierung einer freistehenden Vorlagenfunktion sein ???std::swap
, aber das ist nicht das, was das OP verwendet. Wenn Sie dies tunFirst.swap(Second);
, rufen Sie an,std::vector::swap
was eine andere Funktion ist alsstd::swap
void swap(std::vector& other)
(dhstd::vector<T>
), nicht alstemplate <typename U> void swap(std::vector<U>& other)
(unter der Annahme, dass T ein Typparameter für den Vektor selbst ist).Sie können keine Vektoren zweier verschiedener Typen austauschen, aber es handelt sich um einen Kompilierungsfehler anstelle von UB.
vector::swap
akzeptiert nur Vektoren des gleichen Typs und Allokators.Sie sind sich nicht sicher, ob dies funktioniert, aber wenn Sie einen Vektor mit
Widget2
s vonWidget
s konvertieren möchten , können Sie Folgendes versuchen:Widget2
muss konstruierbar sein vonWidget
.quelle
using std::swap; swap(a, b);
unda.swap(b);
haben genau die gleiche Semantik, wo letztere funktioniert; Zumindest für jeden vernünftigen Typ. Alle Standardtypen sind in dieser Hinsicht vernünftig.Wenn Sie keinen interessanten Allokator verwenden (dh Stateful, nicht immer gleich und nicht beim Container-Swap weitergegeben, siehe
std::allocator_traits
), ist das Austauschen von zweistd::vector
s mit denselben Template-Argumenten nur ein langweiliger Swap von drei Werten (für Kapazität, Größe und Daten-). Zeiger). Und das Austauschen von Basistypen ohne Datenrennen ist sicher und kann nicht geworfen werden.Das garantiert sogar der Standard. Siehe
std::vector::swap()
.quelle