使用 std::vector::swap 方法在 C++ 中交换两个不同的向量是否安全?

Ema*_*ano 31 c++ swap vector stdvector c++11

假设您有以下代码:

#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;
}
Run Code Online (Sandbox Code Playgroud)

想象一下向量不是std::string,但类:

std::vector<Widget> WidgetVector;

std::vector<Widget2> Widget2Vector;
Run Code Online (Sandbox Code Playgroud)

用该std::vector::swap方法交换两个向量是否仍然安全:WidgetVector.swap(Widget2Vector);或者它会导致 UB?

Nat*_*ica 22

是的,交换相同类型的向量是完全安全的。

引擎盖下的向量只是指向向量使用的数据和序列“结束”的几个指针。当您调用 swap 时,您只需在向量之间交换这些指针。因此,您无需担心向量的大小相同。

不能使用 交换不同类型的向量swap。您需要实现自己的函数来进行转换和交换。

  • 您需要更仔细地查看问题的第二部分。 (3认同)

Vla*_*cow 20

这是安全的,因为在交换操作期间没有创建任何内容。仅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;
}
Run Code Online (Sandbox Code Playgroud)

程序输出是

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 
Run Code Online (Sandbox Code Playgroud)

如您所见,只有数据成员ptrn在成员函数 swap 中进行了交换。没有使用额外的资源。

类中使用了类似的方法std::vector

至于这个例子

std::vector<Widget> WidgetVector;

std::vector<Widget2> Widget2Vector;
Run Code Online (Sandbox Code Playgroud)

然后有不同类的对象。成员函数 swap 应用于相同类型的向量。

  • 但是,OP 的“实际”情况又如何,其中被交换的向量属于“不同”类别? (6认同)
  • @AdrianMole 如果为向量的给定类型定义了成员函数 swap。它没有为不同类型的向量定义。它不是模板成员函数。 (4认同)

eer*_*ika 13

使用 std::vector::swap 方法在 C++ 中交换两个不同的向量是否安全?

是的。交换通常被认为是安全的。另一方面,安全是主观的、相对的,可以从不同的角度来考虑。因此,如果不使用上下文增加问题并选择正在考虑的安全类型,就不可能给出令人满意的答案。

使用 std::vector::swap 方法交换两个向量是否仍然安全: WidgetVector.swap(Widget2Vector); 还是会导致UB?

不会有UB。是的,从程序格式错误的意义上说,它仍然是安全的。


Adr*_*ica 7

swap函数被定义为如下:void swap( T& a, T& b );。请注意,ab都是(并且必须是)相同的类型。(没有用这个签名定义这样的函数:void swap( T1& a, T2& b ),因为它没有意义!)

同样,类的swap()成员函数std::vector定义如下:

template<class T1> class vector // Note: simplified from the ACTUAL STL definition
{
//...
public:
    void swap( vector& other );
//...
};
Run Code Online (Sandbox Code Playgroud)

现在,由于函数参数(其形式为:)没有带有模板覆盖的“等效”定义(请参阅函数模板的显式专业化template <typename T2> void swap(std::vector<T2>& other)),因此该参数必须是相同类型(模板)的向量作为'calling' 类(也就是说,它也必须是 a vector<T1>)。

std::vector<Widget>std::vector<Widget2>两种不同的类型,所以调用swap将不能编译,你是否尝试为使用对象的成员函数(如你的代码一样),或者使用专门的的std::swap()取两个函数std:vector对象作为参数。

  • `std::vector::swap` 是一个成员函数,它怎么可能是独立模板函数的特化??? (8认同)
  • @AdrianMole 虽然确实存在“std::swap”的专门化,但这不是OP正在使用的。当你执行 `First.swap(Second);` 时,你调用 [`std::vector::swap`](https://en.cppreference.com/w/cpp/container/vector/swap) 这是一个与 [`std::swap`](https://en.cppreference.com/w/cpp/algorithm/swap) 不同的函数 (2认同)
  • 推理实际上是类似的:成员被定义为 `void swap(std::vector&amp; other)` (即 `std::vector&lt;T&gt;`),而不是 `template &lt;typename U&gt; void swap(std::vector&lt; U&gt;&amp; other)`(假设 T 是向量本身的类型参数)。 (2认同)