C++/STL

[C++20] Span

sseram 2023. 7. 4. 23:35
반응형

공식 문서는 아래.

 

https://en.cppreference.com/w/cpp/container/span

 

std::span - cppreference.com

The class template span describes an object that can refer to a contiguous sequence of objects with the first element of the sequence at position zero. A span can either have a static extent, in which case the number of elements in the sequence is known at

en.cppreference.com

 

C++ 20부터 추가된 기능.

새로운 형태의 컨테이너가 나왔나? 싶어서 살펴봤는데, 그건 아니었다.

이미 있던 기존 인접한 메모리를 가진 배열 비슷한 것들을 가볍고 안전하게 탐색 할 수 있는 방법이라고 한다.

 

 

우리 AI께선 

 

연속된 개체 시퀀스에 대한 간단한 보기를 제공합니다. span은 메모리에서 다시 정렬된 개체를 반복하고 인덱싱하는 안전한 방법을 제공합니다. 기본 제공 배열, std::array 또는 std::vector에 저장된 개체와 같은 경우 일반적으로 포인터와 인덱스 스를 사용하여 개체에 액세스하는 것보다 span을 사용하는 것이 더 안전합니다

 

라고 말씀하셨다.

 

즉, 새롭게 무언갈 만드는 게 아니라, 이미 있는 걸 더 빠르고 간편하고 안전하게 탐색할 수 있게 만들어 준다는 말.

array_ref / array_view 라고 생각하면 편하지 않을까..?

 


 

 

#include <span>
#include <iostream>

using namespace std;

int main()
{
    int a[] = { 0,1,2 };
    span<int> mySpan(a);

    for (auto&& i : mySpan) {
        cout << i << endl;
    }
    
    mySpan[1] = 2;

    return 0;
}

 

 

예시론 이런 코드가 있을 수 있겠다.

 

전통적인 배열을 만드는 방식으로 a 배열을 만들었다. 그리고 a 배열을 통해 그것을 탐색 할 수 있는 span 형태의 mySpan을 만들었다. 그러고 나면 간단하게 실제 해당 배열을 다루는 것 처럼 mySpan을 다룰 수 있다. for문을 통하여 내부 요소들을 꺼내 사용도 가능하고, 직접 그 위치에 가서 값을 변경할 수도 있다.

 

#include <span>
#include <vector>
#include <iostream>

using namespace std;

int main()
{
    vector<int> a = { 0,1,2 };
    span<int> mySpan(a);

    
    for (auto&& i : mySpan) {
        cout << i << endl;
    }

    mySpan[0] = 11;
    a[2] = 22;

    for (auto&& i : mySpan) {
        cout << i << endl;
    }

    return 0;
}

 

당연히 서로 연동도 된다.

 

 


 

그래서 언제 사용하면 좋냐?

 

 

- raw array 를 안전하게 읽을 때

더보기
#include <span>

using namespace std;

void read(span<int> buffer) {
    for (auto&& i : buffer) {
        cout << i << endl;
    }
}

int main()
{
    int a[] = { 1,2,3 };
    read(a);

    return 0;
}

 

 

- vector<string> 을 가볍게 넘기고 싶을 때

더보기
#include <span>
#include <vector>
#include <iostream>

using namespace std;

void read(span<string> buffer) {
    for (auto&& i : buffer) {
        cout << i << endl;
    }
}

// 이제 이런 식으로 하지 않아도 효율적이다!
//void read(const vector<string>& buffer) {
//    for (auto&& i : buffer) {
//        cout << i << endl;
//    }
//}

int main()
{
    vector<string> somevec {"aa", "bb", "cc", "dd"};

    read(somevec);

    return 0;
}

 

- static하게 버그를 잡아내고 싶을 때

더보기
#include <span>
#include <vector>
#include <algorithm>
#include <iostream>

using namespace std;

template<class T, std::size_t N, std::size_t M>
constexpr bool contains(std::span<T, N> span, std::span<T, M> sub)
{
    return std::search(span.begin(), span.end(), sub.begin(), sub.end()) != span.end();
}

int main()
{
    constexpr int a[]{ 0, 1, 2, 3, 4, 5, 6, 7, 8 };

    static_assert(contains(std::span{a}, std::span{a + 1, 4}) and 
        contains(std::span{a, 8}, std::span{a, 9}));   // <<< error!

    return 0;
}

 

가 있겠다!

보통, 탐색 할 떄 span을 자주 쓰는 듯 하다.

 

 

 

물론 span 자체가 인접한 메모리에 붙어있고, start, end iterator를 가지고 있는 (begin(), end()) 것들만 사용이 가능하니, 주의해서 사용하면 좋을 듯 하다!

 

 

 

 

* 잘못된 정보는 알려주시면 감사한 마음으로 수정하겠습니다.

반응형

'C++ > STL' 카테고리의 다른 글

[C++17] std::variant  (1) 2023.11.12
[C++] remove(remove_if) vs erase(erase_if)  (0) 2023.07.11
[C++] Priority_queue  (0) 2023.06.04
[C++17] Optional  (0) 2023.05.28
[C++20] Concepts  (1) 2023.05.23