"스팬"이란 무엇이며 언제 사용해야합니까?


237

최근 span<T>에 내 코드에서의 사용 제안을 얻었 거나 사이트에서 span일종의 컨테이너 를 사용하는 답변을 보았습니다 . 그러나 C ++ 17 표준 라이브러리에서 이와 같은 것을 찾을 수 없습니다.

그렇다면이 비밀은 무엇이며 span<T>, 비표준 인 경우 왜 사용하는 것이 좋은가?


std::spanC ++ 17 또는 C ++ 20에 적용됩니다. 또한 P0122R5, span : 객체 시퀀스에 대한 범위 안전 뷰를 참조하십시오 . 해당 언어를 타겟팅 하시겠습니까? 컴파일러가 따라 잡는 데 몇 년이 걸릴 것입니다.
jww

6
@jww : 스팬의 꽤 C ++ (11)과 함께 사용할 수 ... 등입니다 gsl::span보다는 std::span. 아래의 답변도 참조하십시오.
einpoklum

또한 cppreference.com에 문서화되어 있습니다. en.cppreference.com/w/cpp/container/span
Keith Thompson

1
@KeithThompson : 2017 년이 아니었다 ...
einpoklum

@jww 모든 컴파일러는 이제 C ++ 20 모드에서 std :: span <>을 지원합니다. 그리고 span은 많은 타사 라이브러리에서 사용할 수 있습니다. 당신이 옳았습니다-그것은 2 년입니다. 정확한 2 년.
콘 탄고

답변:


272

무엇입니까?

A span<T>는 :

  • T메모리 어딘가에 연속 된 유형의 값 시퀀스를 매우 가볍게 추상화 한 것입니다 .
  • 기본적으로 struct { T * ptr; std::size_t length; }편리한 방법이 많이 있습니다.
  • 비 소유 유형 (즉, " 값 유형"이 아닌 "참조 유형") : 어떤 것도 할당하거나 할당을 해제하지 않으며 스마트 포인터를 유지하지 않습니다.

이전에는로 알려져 있었고 이전에는로도 알려 array_view졌습니다 array_ref.

언제 사용해야합니까?

먼저 사용 하지 않을 때 :

  • 코드에서 사용하지 마십시오 것은 단지 시작 및 끝 반복자의 쌍을 수있는 등 std::sort, std::find_if, std::copy그 슈퍼 제네릭 템플릿의 모든 기능.
  • 코드에 적합한 표준 라이브러리 컨테이너 (또는 Boost 컨테이너 등)가있는 경우 사용하지 마십시오. 그것들을 대체하기위한 것이 아닙니다.

이제 실제로 사용할 때 :

사용 span<T>(각각 span<const T>) 대신 독립 T*(각각 const T*있는 당신이 길이 값이). 따라서 다음과 같은 기능을 대체하십시오.

  void read_into(int* buffer, size_t buffer_size);

와:

  void read_into(span<int> buffer);

왜 사용해야합니까? 왜 좋은가요?

아, 스팬은 대단해! 사용 span...

  • 즉, 멋진 포밍 아웃 표준 라이브러리 컨테이너와 같이 포인터 + 길이 / 시작 + 끝 포인터 조합으로 작업 할 수 있습니다.

    • for (auto& x : my_span) { /* do stuff */ }
    • std::find_if(my_span.begin(), my_span.end(), some_predicate);

    ...하지만 대부분의 컨테이너 클래스에서 발생하는 오버 헤드는 전혀 없습니다.

  • 컴파일러가 때때로 더 많은 작업을 수행하도록합니다. 예를 들면 다음과 같습니다.

    int buffer[BUFFER_SIZE];
    read_into(buffer, BUFFER_SIZE);

    이된다 :

    int buffer[BUFFER_SIZE];
    read_into(buffer);

    ... 당신이 원하는 것을 할 것입니다. 지침 P.5 참조 .

  • const vector<T>&데이터가 메모리에서 연속적 일 것으로 예상 될 때 함수 에 전달 하는 것의 합리적인 대안 입니다. 더 이상 전능 한 C ++ 전문가들에게 꾸짖지 않아도됩니다!

  • 정적 분석을 용이하게하므로 컴파일러가 바보 같은 버그를 잡는 데 도움을 줄 수 있습니다.
  • 런타임 경계 검사를위한 디버그 컴파일 계측을 허용합니다 (예 : span메소드에는 경계 검사 코드가 있습니다 #ifndef NDEBUG... #endif)
  • 은 (span을 사용하는) 코드가 지정된 메모리를 소유하지 않음을 나타냅니다.

C ++ 핵심 지침span 에서 찾을 수있는 s 사용에 대한 동기 부여가 더 많지만 드리프트를 잡습니다.

표준 라이브러리에없는 이유는 무엇입니까 (C ++ 17 기준)?

표준 라이브러리에 있지만 C ++ 20에서만 가능합니다. 그 이유는 C ++ 핵심 지침 프로젝트 와 관련하여 2015 년 이후에야만 구체화 되고있는 현재의 형태로 여전히 새롭기 때문입니다.

표준 라이브러리에없는 경우 어떻게 사용합니까?

핵심 지침 의 지원 라이브러리 (GSL) 의 일부입니다 . 구현 :

  • Microsoft / Neil Macintosh의 GSL 에는 독립형 구현이 포함되어 있습니다.gsl/span
  • GSL-Lite는를 포함 하여 전체 GSL의 단일 헤더 구현입니다 (크지 않고 걱정하지 마십시오) span<T>.

GSL 구현은 일반적으로 C ++ 14 지원을 구현하는 플랫폼을 가정합니다 [ 14 ]. 이러한 대체 단일 헤더 구현은 GSL 기능에 의존하지 않습니다.

이러한 다른 범위 구현에는 제공되는 메소드 / 지원 기능에 약간의 차이가 있습니다. C ++ 20의 표준 라이브러리에 들어가는 버전과 약간 다를 수도 있습니다.


추가 자료 : C ++ 17, P0122R7 이전의 최종 공식 제안에서 모든 세부 사항과 설계 고려 사항을 찾을 수 있습니다. span : Neal Macintosh 및 Stephan J. Lavavej 의 객체 시퀀스에 대한 범위 안전 뷰 . 그래도 조금 길다. 또한 C ++ 20에서는 범위 비교 의미가 변경되었습니다 ( Tony van Eerd 의이 짧은 논문 에 이어).


2
일반 범위 (반복자 + 센티넬 및 반복자 + 길이, 아마도 반복자 + 센티넬 + 길이 지원)를 표준화하고 범위를 간단한 typedef로 만드는 것이 더 합리적입니다. 보다 일반적인 것이기 때문입니다.
중복 제거기

3
@ 중복 제거기 : 범위가 C ++로오고 있지만 Eric Niebler의 현재 제안은 개념을 지원해야합니다. C ++ 20 이전에는 그렇지 않습니다.
einpoklum

8
@ HảiPhạmLê : 배열이 포인터로 즉시 붕괴되지 않습니다. 시도해 std::cout << sizeof(buffer) << '\n'보면 100 sizeof (int)가 나타납니다.
einpoklum

4
@Jim std::array은 컨테이너이며 값을 소유합니다. span비 소유
Caleth

3
@Jim : std::array완전히 다른 짐승입니다. Caleth가 설명했듯이 길이는 컴파일 타임에 고정되며 참조 유형이 아닌 값 유형입니다.
einpoklum

1

@einpoklum는 무엇 도입 꽤 좋은 작업 수행 span입니다 여기에 그의 대답을 . 그러나 그의 답변을 읽은 후에도 새로운 사람이 다음과 같이 완전히 대답하지 않은 일련의 생각을 가진 질문을 여전히 쉽게 가질 수 있습니다.

  1. 어떻게 spanC 배열과 다른가? 왜 그중 하나를 사용하지 않습니까? 크기가 알려진 것 중 하나 일뿐입니다 ...
  2. 잠깐, 그 소리 std::array는 어떻게 들립 span니까?
  3. 아, 생각 나게하는, a는 아니다 std::vector유사한 std::array너무?
  4. 난 너무 혼란 스러워요. :( 무엇입니까 span?

따라서 여기에 대한 추가 명확성이 있습니다.

답변에 대한 직접적인 견적 --BOLD에 대한 추가 사항 :

무엇입니까?

A span<T>는 :

  • T메모리 어딘가에 연속 된 유형의 값 시퀀스를 매우 가볍게 추상화 한 것입니다 .
  • 기본적으로 많은 편리한 메소드를 가진 단일 구조체 { T * ptr; std::size_t length; }입니다. (주의 사항이 확연히 다른 std::array<>A가 있으므로 span방법 접근 편의를 비교할 수있게 std::array비아 입력 포인터T 입력의 길이 (요소 수) T, 반면, std::array하나 개 이상의 보유 실제 컨테이너 유형을 T).
  • 비 소유 유형 (즉, " 값 유형"이 아닌 "참조 유형") : 어떤 것도 할당하거나 할당을 해제하지 않으며 스마트 포인터를 유지하지 않습니다.

이전에는로 알려져 있었고 이전에는로도 알려 array_view졌습니다 array_ref.

그 대담한 부분은 이해 하는 데 중요 하므로 놓치거나 잘못 읽지 마십시오! A span는 구조체의 C- 배열이 아니며, 유형의 C- 배열의 배열과 배열의 T길이를 더한 구조체도 아니며 (이것은 std::array 컨테이너 가 본질적인 것임 ), NOR도 포인터 구조체의 C- 배열입니다. 유형 T더한 길이 오히려 그것은 인 하나 하나 함유 구조체 타입 포인터T길이 는 IS, (입력 요소의 개수 T포인터가 입력 할 수있는 연속적인 메모리 블록) T에 점! 이런 식으로, 당신이 사용하여 추가 한 유일한 오버 헤드span포인터와 길이를 저장하는 변수 및 제공하는 편리한 접근 자 함수 span입니다.

이것은 달리입니다 std::array<>때문에 std::array<>전체 연속 블록에 대한 실제 메모리를 할당하고는 달리 std::vector<>A가 있기 때문에 std::vector기본적으로 단지 std::array도한다는 것을 동적 증가 할 때마다이가 가득 (보통 크기의 두 배) 당신은 그것을 다른 무언가를 추가하려고 . A는 std::array크기가 고정되고, A는 span심지어에, 메모리 블록 단지 점은, 메모리 블록이 얼마나 오래 알고 가리키는 블록의 메모리를 관리하지 않는 데이터 유형은 C 배열에 알고 메모리에서, 그리고 인접한 메모리의 요소들과 함께 작업하기위한 편리한 접근 자 기능을 제공합니다 .

그것은 이다 는 C의 일부 ++ 표준 :

std::spanC ++ 20 기준으로 C ++ 표준의 일부입니다. https://en.cppreference.com/w/cpp/container/span 문서를 읽을 수 있습니다 . 오늘absl::Span<T>(array, length) C ++ 11 이상에서 Google을 사용하는 방법을 보려면 아래를 참조하십시오.

요약 설명 및 키 참조 :

  1. std::span<T, Extent>( Extent= "시퀀스의 요소 수 또는 std::dynamic_extent동적 인 경우"스팬은 메모리를 가리키고 액세스하기는 쉽지만 관리하지는 않습니다!) :
    1. https://en.cppreference.com/w/cpp/container/span
  2. std::array<T, N>( 고정 크기입니다 N!) :
    1. https://en.cppreference.com/w/cpp/container/array
    2. http://www.cplusplus.com/reference/array/array/
  3. std::vector<T> (필요에 따라 자동으로 크기가 동적으로 커짐) :
    1. https://en.cppreference.com/w/cpp/container/vector
    2. http://www.cplusplus.com/reference/vector/vector/

오늘span C ++ 11 이상에서 어떻게 사용할 수 있습니까 ?

Google은 "Abseil"라이브러리 형태로 내부 C ++ 11 라이브러리를 오픈 소스로 제공했습니다. 이 라이브러리는 C ++ 14에서 C ++ 20 이상으로 C ++ 11 이상에서 작동하는 기능을 제공하여 내일의 기능을 사용할 수 있습니다. 그들은 말합니다 :

C ++ 표준과의 호환성

Google은 C ++ 14, C ++ 17 이상에 통합 된 기능과 일치하거나 밀접하게 일치하는 많은 추상화를 개발했습니다. 이러한 추상화의 Abseil 버전을 사용하면 코드가 아직 C ++ 11 이후 환경에서 사용할 준비가되지 않아도 이러한 기능에 액세스 할 수 있습니다.

주요 리소스 및 링크는 다음과 같습니다.

  1. 메인 사이트 : https://abseil.io/
  2. https://abseil.io/docs/cpp/
  3. GitHub 리포지토리 : https://github.com/abseil/abseil-cpp
  4. span.h헤더 및 absl::Span<T>(array, length)템플릿 클래스 : https://github.com/abseil/abseil-cpp/blob/master/absl/types/span.h#L189

1
중요하고 유용한 정보를 가져다 주실 것입니다. 감사합니다!
Gui Lima
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.