繁体   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