簡體   English   中英

使用 std::vector::swap 方法在 C++ 中交換兩個不同的向量是否安全?

[英]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 

如您所見,只有數據成員ptrn在成員函數 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 ); . 請注意, ab都是(並且必須是)相同的類型 (沒有用這個簽名定義這樣的函數: 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM