Aman karena tidak ada yang dibuat selama operasi swap. Hanya anggota data kelas std::vector
yang ditukar.
Pertimbangkan program demonstratif berikut yang memperjelas bagaimana objek kelas std::vector
dipertukarkan.
#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;
}
Output program adalah
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
Seperti yang Anda lihat hanya anggota data ptr
dan n
ditukar dalam fungsi swap anggota. Tidak ada sumber daya tambahan yang digunakan.
Pendekatan serupa digunakan di kelas std::vector
.
Adapun contoh ini
std::vector<Widget> WidgetVector;
std::vector<Widget2> Widget2Vector;
lalu ada objek dari kelas yang berbeda. Fungsi swap anggota diterapkan pada vektor dengan tipe yang sama.
Ya, ini sangat aman untuk menukar vektor dari jenis yang sama.
Vektor di bawah tenda hanyalah beberapa petunjuk yang menunjuk ke data yang digunakan vektor dan "akhir" urutannya. Saat Anda memanggil swap, Anda cukup menukar pointer tersebut di antara vektor. Anda tidak perlu khawatir bahwa vektor berukuran sama karena ini.
Vektor dari berbagai jenis tidak dapat ditukar menggunakan
swap
. Anda harus mengimplementasikan fungsi Anda sendiri yang melakukan konversi dan pertukaran.sumber
2
. Diperbarui.Iya. Bertukar secara umum dapat dianggap aman. Di sisi lain, keselamatan bersifat subyektif dan relatif dan dapat dipertimbangkan dari berbagai perspektif. Karena itu, tidak mungkin untuk memberikan jawaban yang memuaskan tanpa menambah pertanyaan dengan konteks, dan memilih jenis keamanan apa yang dipertimbangkan.
Tidak akan ada UB. Ya, itu masih aman dalam arti bahwa program ini dibuat dengan buruk.
sumber
The
swap
Fungsi didefinisikan sebagai berikut:void swap( T& a, T& b );
. Perhatikan di sini bahwa keduanyaa
danb
(dan harus ) jenis yang sama . (Tidak ada fungsi yang didefinisikan dengan tanda tangan ini:,void swap( T1& a, T2& b )
karena tidak masuk akal!)Demikian pula,
swap()
fungsi anggotastd::vector
kelas didefinisikan sebagai berikut:Sekarang, karena tidak ada definisi 'setara' dengan override templat (lihat Spesialisasi eksplisit templat fungsi ) untuk parameter fungsi (yang akan berbentuk
template <typename T2> void swap(std::vector<T2>& other)
:), parameter itu harus berupa vektor dengan tipe yang sama (templat) seperti kelas 'pemanggilan' (yaitu, harus juga avector<T1>
).Anda
std::vector<Widget>
danstd::vector<Widget2>
dua yang berbeda jenis, sehingga panggilan untukswap
tidak akan mengkompilasi, apakah Anda mencoba untuk menggunakan fungsi anggota baik objek (seperti kode Anda tidak), atau menggunakan spesialisasi daristd::swap()
fungsi yang mengambil duastd:vector
benda sebagai parameter.sumber
std::vector::swap
itu fungsi anggota, bagaimana bisa itu menjadi spesialisasi fungsi templat yang berdiri sendiri ???std::swap
, bukan itu yang digunakan OP. Ketika Anda melakukannyaFirst.swap(Second);
, Anda memanggilstd::vector::swap
fungsi yang berbeda daristd::swap
void swap(std::vector& other)
(yaitustd::vector<T>
), bukan sebagaitemplate <typename U> void swap(std::vector<U>& other)
(dengan asumsi T adalah parameter tipe untuk vektor itu sendiri).Anda tidak dapat menukar vektor dari dua jenis tetapi ini merupakan kesalahan kompilasi alih-alih UB.
vector::swap
hanya menerima vektor dengan jenis dan pengalokasi yang sama.Tidak yakin apakah ini akan berhasil, tetapi jika Anda ingin vektor yang mengandung
Widget2
s dikonversi dariWidget
s Anda dapat mencoba ini:Widget2
harus dipindahkan dari yang konstruktifWidget
.sumber
using std::swap; swap(a, b);
dana.swap(b);
memiliki semantik yang sama persis di mana yang terakhir bekerja; setidaknya untuk semua jenis waras. Semua tipe standar waras dalam hal itu.Kecuali jika Anda menggunakan pengalokasi yang menarik (artinya stateful, tidak selalu sama, dan tidak disebarkan pada swap kontainer, lihat
std::allocator_traits
), bertukar duastd::vector
s dengan argumen templat yang sama hanyalah pertukaran membosankan dari tiga nilai (untuk kapasitas, ukuran, dan data- pointer). Dan bertukar tipe dasar, tidak ada perlombaan data, aman dan tidak bisa dilempar.Itu bahkan dijamin oleh standar. Lihat
std::vector::swap()
.sumber