공식 문서는 아래.
https://en.cppreference.com/w/cpp/container/span
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 |