[英]Is it safe to swap two different vectors in C++, using the std::vector::swap method?
假設您有以下代碼:
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> First{"example", "second" , "C++" , "Hello world" };
std::vector<std::string> Second{"Hello"};
First.swap(Second);
for(auto a : Second) std::cout << a << "\n";
return 0;
}
想象一下向量不是std::string
,而是類:
std::vector<Widget> WidgetVector;
std::vector<Widget2> Widget2Vector;
使用std::vector::swap
方法交換兩個向量是否仍然安全: WidgetVector.swap(Widget2Vector);
還是會導致UB?
是的,交換相同類型的向量是完全安全的。
引擎蓋下的向量只是指向向量使用的數據和序列“結束”的幾個指針。 當您調用 swap 時,您只需在向量之間交換這些指針。 因此,您無需擔心向量的大小相同。
不能使用swap
不同類型的向量。 您需要實現自己的函數來進行轉換和交換。
這是安全的,因為在交換操作期間沒有創建任何內容。 僅交換類std::vector
數據成員。
考慮下面的演示程序,它清楚地說明了類std::vector
對象是如何交換的。
#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;
}
程序輸出是
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
如您所見,只有數據成員ptr
和n
在成員函數 swap 中交換。 沒有使用額外的資源。
類std::vector
使用了類似的方法。
至於這個例子
std::vector<Widget> WidgetVector;
std::vector<Widget2> Widget2Vector;
然后有不同類的對象。 成員函數 swap 應用於相同類型的向量。
使用 std::vector::swap 方法在 C++ 中交換兩個不同的向量是否安全?
是的。 交換通常被認為是安全的。 另一方面,安全是主觀的、相對的,可以從不同的角度來考慮。 因此,如果不使用上下文增加問題並選擇正在考慮的安全類型,就不可能給出令人滿意的答案。
使用 std::vector::swap 方法交換兩個向量是否仍然安全: WidgetVector.swap(Widget2Vector); 還是會導致UB?
不會有UB。 是的,從程序格式錯誤的意義上說,它仍然是安全的。
swap
函數定義如下: void swap( T& a, T& b );
. 請注意, a
和b
都是(並且必須是)相同的類型。 (沒有用這個簽名定義這樣的函數: void swap( T1& a, T2& b )
,因為它沒有意義!)
同樣, std::vector
類的swap()
成員函數定義如下:
template<class T1> class vector // Note: simplified from the ACTUAL STL definition
{
//...
public:
void swap( vector& other );
//...
};
現在,作為有與模板改寫沒有“等效”定義(見的函數模板顯特)為函數參數(這將是以下形式: template <typename T2> void swap(std::vector<T2>& other)
),該參數必須是與“調用”類相同類型(模板)的向量(也就是說,它也必須是vector<T1>
)。
您的std::vector<Widget>
和std::vector<Widget2>
是兩種不同的類型,因此無論您嘗試使用任一對象的成員函數(如您的代碼那樣),對swap
的調用都不會編譯,或者使用專業化std::swap()
函數,它需要兩個std:vector
對象作為參數。
您不能交換兩種不同類型的向量,但這是編譯錯誤而不是 UB。 vector::swap
只接受相同類型和分配器的向量。
不確定這是否可行,但是如果您想要一個包含從Widget
轉換而來的Widget2
的向量,您可以嘗試以下操作:
std::vector<Widget2> Widget2Vector(
std::make_move_iterator(WidgetVector.begin()),
std::make_move_iterator(WidgetVector.end())
);
Widget2
必須可以從Widget
移動構造。
using std::swap; swap(a, b);
和a.swap(b);
具有與后者完全相同的語義; 至少對於任何理智的類型。 在這方面,所有標准類型都是理智的。
除非你使用一個有趣的分配器(意思是有狀態的,不總是相等的,並且不在容器交換上傳播,請參閱std::allocator_traits
),交換兩個具有相同模板參數的std::vector
只是三個值的無聊交換(容量、大小和數據指針)。 交換基本類型,沒有數據競爭,是安全的,不能拋出。
這甚至由標准保證。 見std::vector::swap()
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.