std :: vector :: swap 메소드를 사용하여 C ++에서 두 개의 다른 벡터를 바꾸는 것이 안전합니까?


30

다음 코드가 있다고 가정하십시오.

#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로 이어질까요?

답변:


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;
}

프로그램 출력은

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멤버 함수 스왑으로 교체된다. 추가 리소스가 사용되지 않습니다.

비슷한 접근법이 클래스에서 사용됩니다 std::vector.

이 예는

std::vector<Widget> WidgetVector;

std::vector<Widget2> Widget2Vector;

다른 클래스의 객체가 있습니다. 멤버 함수 스왑은 동일한 유형의 벡터에 적용됩니다.


6
그러나 교환되는 벡터가 다른 클래스 의 OP의 실제 사례는 무엇입니까?
Adrian Mole

4
@AdrianMole 주어진 벡터 유형에 대해 정의 된 경우 멤버 함수 스왑. 다른 유형의 벡터에 대해서는 정의되어 있지 않습니다. 템플릿 멤버 함수가 아닙니다.
모스크바에서 블라드

"스왑은 동일한 유형의 벡터에 적용됩니다" "is"와 "applied"사이에 "only"를 추가해야합니다.
SS Anne

물론 스테이트 풀 할당자는 상황을 바꿀 수 있습니다.
중복 제거기

21

예, 이것은 동일한 유형의 벡터를 바꾸는 데 완벽하게 안전합니다.

후드 아래의 벡터는 벡터가 사용하는 데이터와 시퀀스의 "종료"를 가리키는 몇 가지 포인터입니다. 스왑을 호출하면 벡터 사이의 포인터를 교환하기 만하면됩니다. 이로 인해 벡터의 크기가 동일하다는 것을 걱정할 필요가 없습니다.

다른 유형의 벡터는을 사용하여 교환 할 수 없습니다 swap. 변환 및 스와핑을 수행하는 고유 한 기능을 구현해야합니다.


3
질문의 두 번째 부분을 자세히 살펴 봐야합니다.
마크 랜섬

@MarkRansom Yep. 보고 싶었습니다 2. 업데이트되었습니다.
NathanOliver

13

std :: vector :: swap 메소드를 사용하여 C ++에서 두 개의 다른 벡터를 바꾸는 것이 안전합니까?

예. 스와핑은 일반적으로 안전하다고 간주 될 수 있습니다. 반면에 안전은 주관적이고 상대적이며 다른 관점에서 고려할 수 있습니다. 따라서 상황에 따라 질문을 보완하고 어떤 종류의 안전을 고려하지 않고 만족스러운 대답을하는 것은 불가능합니다.

두 벡터를 std :: vector :: swap 메소드로 교체해도 안전합니까? WidgetVector.swap (Widget2Vector); 아니면 UB로 이어질까요?

UB는 없습니다. 예, 프로그램이 잘못 구성되어 있다는 점에서 여전히 안전합니다.


7

swap다음 함수가 정의된다 void swap( T& a, T& b );. 여기에 참고 모두 a하고 b있다 (그리고 수)에 동일한 유형 . (이 서명으로 정의 된 기능은 없습니다 :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 );
//...
};

이제 함수 매개 변수 (형식 :)에 대한 템플리트 대체 ( 함수 템플리트의 명시 적 특수화 참조)가있는 '동등한'정의가 없으므로 template <typename T2> void swap(std::vector<T2>& other)해당 매개 변수 다음과 같은 유형 (템플릿)의 벡터 여야합니다 . 'calling'클래스 (즉, 또한이어야 함 vector<T1>)

귀하 std::vector<Widget>std::vector<Widget2>두 가지 서로 다른 호출이 때문에, 종류 swap당신이 (당신의 코드처럼) 두 객체의 멤버 함수를 사용하려고 여부, 컴파일, 또는 사용하지 않을 것입니다 전문std::swap()이 걸리는 기능을 std:vector매개 변수로 객체.


8
std::vector::swap멤버 함수는 어떻게 독립형 템플릿 함수를 전문화 할 수 있습니까 ???
아콩 카과

1
올바른 결과, 잘못된 추론.
NathanOliver

2
@AdrianMole에 대한 전문화는 있지만 std::swapOP가 사용하는 것은 아닙니다. 당신이 할 경우 First.swap(Second);, 당신은 전화를 std::vector::swap다른 기능에서 인std::swap
NathanOliver

1
죄송합니다, 내 나쁜 ... 링크가 바로 std :: swap 전문화 벡터 문서로 연결됩니다. 그러나 이는 멤버 함수 와 다르며 존재하며 문제가됩니다 (단지).
아콩 카과

2
추론은 실제로 유사합니다. 멤버는 void swap(std::vector& other)( 벡터 자체의 유형 매개 변수라고 가정 std::vector<T>하지 않음)가 아니라 (즉 ) 로 정의됩니다 template <typename U> void swap(std::vector<U>& other).
Aconcagua

4

서로 다른 두 가지 유형의 벡터를 바꿀 수는 없지만 UB 대신 컴파일 오류입니다. vector::swap동일한 유형 및 할당 자의 벡터 만 허용합니다.

이것이 작동하는지 확실하지 않지만을 포함하는 벡터를 Widget2s에서 변환 Widget하려면 다음을 시도하십시오.

std::vector<Widget2> Widget2Vector(
    std::make_move_iterator(WidgetVector.begin()),
    std::make_move_iterator(WidgetVector.end())
);

Widget2에서 생성 가능한 이동해야합니다 Widget.


0

using std::swap; swap(a, b);그리고 a.swap(b);후자의 작품 동일한 의미를 갖고; 적어도 제정신 유형에 대해. 그런 점에서 모든 표준 유형은 제정신입니다.

흥미로운 할당자를 사용하지 않는 한 (상태 저장, 항상 같지 않고 컨테이너 스왑에서 전파되지 않음, 참조 std::allocator_traits), std::vector동일한 템플릿 인수로 두 s를 바꾸는 것은 용량, 크기 및 데이터에 대한 세 가지 값의 지루한 스왑입니다. 바늘). 그리고 데이터 레이스가없는 기본 유형을 바꾸는 것은 안전하며 던질 수 없습니다.

그것은 심지어 표준에 의해 보장됩니다. 참조하십시오 std::vector::swap().

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.