최근 span<T>
에 내 코드에서의 사용 제안을 얻었 거나 사이트에서 span
일종의 컨테이너 를 사용하는 답변을 보았습니다 . 그러나 C ++ 17 표준 라이브러리에서 이와 같은 것을 찾을 수 없습니다.
그렇다면이 비밀은 무엇이며 span<T>
, 비표준 인 경우 왜 사용하는 것이 좋은가?
gsl::span
보다는 std::span
. 아래의 답변도 참조하십시오.
최근 span<T>
에 내 코드에서의 사용 제안을 얻었 거나 사이트에서 span
일종의 컨테이너 를 사용하는 답변을 보았습니다 . 그러나 C ++ 17 표준 라이브러리에서 이와 같은 것을 찾을 수 없습니다.
그렇다면이 비밀은 무엇이며 span<T>
, 비표준 인 경우 왜 사용하는 것이 좋은가?
gsl::span
보다는 std::span
. 아래의 답변도 참조하십시오.
답변:
A span<T>
는 :
T
메모리 어딘가에 연속 된 유형의 값 시퀀스를 매우 가볍게 추상화 한 것입니다 .struct { T * ptr; std::size_t length; }
편리한 방법이 많이 있습니다.이전에는로 알려져 있었고 이전에는로도 알려 array_view
졌습니다 array_ref
.
먼저 사용 하지 않을 때 :
std::sort
, std::find_if
, std::copy
그 슈퍼 제네릭 템플릿의 모든 기능.이제 실제로 사용할 때 :
사용
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
)C ++ 핵심 지침span
에서 찾을 수있는 s 사용에 대한 동기 부여가 더 많지만 드리프트를 잡습니다.
표준 라이브러리에 있지만 C ++ 20에서만 가능합니다. 그 이유는 C ++ 핵심 지침 프로젝트 와 관련하여 2015 년 이후에야만 구체화 되고있는 현재의 형태로 여전히 새롭기 때문입니다.
핵심 지침 의 지원 라이브러리 (GSL) 의 일부입니다 . 구현 :
gsl/span
span<T>
.GSL 구현은 일반적으로 C ++ 14 지원을 구현하는 플랫폼을 가정합니다 [ 14 ]. 이러한 대체 단일 헤더 구현은 GSL 기능에 의존하지 않습니다.
martinmoene/span-lite
C ++ 98 이상이 필요합니다tcbrindle/span
C ++ 11 이상이 필요합니다이러한 다른 범위 구현에는 제공되는 메소드 / 지원 기능에 약간의 차이가 있습니다. C ++ 20의 표준 라이브러리에 들어가는 버전과 약간 다를 수도 있습니다.
추가 자료 : C ++ 17, P0122R7 이전의 최종 공식 제안에서 모든 세부 사항과 설계 고려 사항을 찾을 수 있습니다. span : Neal Macintosh 및 Stephan J. Lavavej 의 객체 시퀀스에 대한 범위 안전 뷰 . 그래도 조금 길다. 또한 C ++ 20에서는 범위 비교 의미가 변경되었습니다 ( Tony van Eerd 의이 짧은 논문 에 이어).
std::cout << sizeof(buffer) << '\n'
보면 100 sizeof (int)가 나타납니다.
std::array
은 컨테이너이며 값을 소유합니다. span
비 소유
std::array
완전히 다른 짐승입니다. Caleth가 설명했듯이 길이는 컴파일 타임에 고정되며 참조 유형이 아닌 값 유형입니다.
@einpoklum는 무엇 도입 꽤 좋은 작업 수행 span
입니다 여기에 그의 대답을 . 그러나 그의 답변을 읽은 후에도 새로운 사람이 다음과 같이 완전히 대답하지 않은 일련의 생각을 가진 질문을 여전히 쉽게 가질 수 있습니다.
span
C 배열과 다른가? 왜 그중 하나를 사용하지 않습니까? 크기가 알려진 것 중 하나 일뿐입니다 ...std::array
는 어떻게 들립 span
니까?std::vector
유사한 std::array
너무?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 배열에 알고 메모리에서, 그리고 인접한 메모리의 요소들과 함께 작업하기위한 편리한 접근 자 기능을 제공합니다 .
std::span
C ++ 20 기준으로 C ++ 표준의 일부입니다. https://en.cppreference.com/w/cpp/container/span 문서를 읽을 수 있습니다 . 오늘absl::Span<T>(array, length)
C ++ 11 이상에서 Google을 사용하는 방법을 보려면 아래를 참조하십시오.
std::span<T, Extent>
( Extent
= "시퀀스의 요소 수 또는 std::dynamic_extent
동적 인 경우"스팬은 메모리를 가리키고 액세스하기는 쉽지만 관리하지는 않습니다!) :
std::array<T, N>
( 고정 크기입니다 N
!) :
std::vector<T>
(필요에 따라 자동으로 크기가 동적으로 커짐) :
span
C ++ 11 이상에서 어떻게 사용할 수 있습니까 ?Google은 "Abseil"라이브러리 형태로 내부 C ++ 11 라이브러리를 오픈 소스로 제공했습니다. 이 라이브러리는 C ++ 14에서 C ++ 20 이상으로 C ++ 11 이상에서 작동하는 기능을 제공하여 내일의 기능을 사용할 수 있습니다. 그들은 말합니다 :
C ++ 표준과의 호환성
Google은 C ++ 14, C ++ 17 이상에 통합 된 기능과 일치하거나 밀접하게 일치하는 많은 추상화를 개발했습니다. 이러한 추상화의 Abseil 버전을 사용하면 코드가 아직 C ++ 11 이후 환경에서 사용할 준비가되지 않아도 이러한 기능에 액세스 할 수 있습니다.
주요 리소스 및 링크는 다음과 같습니다.
span.h
헤더 및 absl::Span<T>(array, length)
템플릿 클래스 : https://github.com/abseil/abseil-cpp/blob/master/absl/types/span.h#L189
std::span
C ++ 17 또는 C ++ 20에 적용됩니다. 또한 P0122R5, span : 객체 시퀀스에 대한 범위 안전 뷰를 참조하십시오 . 해당 언어를 타겟팅 하시겠습니까? 컴파일러가 따라 잡는 데 몇 년이 걸릴 것입니다.