CodeNote
Coding Note
CodeNote
전체 방문자
오늘
어제
  • 전체 보기 (35)
    • C++ (33)
      • Modern C++ (12)
      • Modern C++ STL (0)
      • Thread (16)
      • Thread (Async) (5)
    • 디자인패턴 (0)
    • Algorithm (2)
    • Electron (0)
    • Python (0)

블로그 메뉴

  • 홈
  • Github
  • 태그
  • 방명록

공지사항

인기 글

태그

  • mutex
  • Free
  • LOCK
  • C++ #Memory
  • 자료구조
  • C++

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
CodeNote

Coding Note

[C++20] std::span
C++/Modern C++

[C++20] std::span

2022. 10. 1. 21:25

std::span 

C++ 20부터 추가된 연속된 메모리 공간을 추상화한 컨테이너다. 이러한 연속적인 공간을 갖는 컨테이너로는 vector, array, string 등이 있다.

 

 

std::vector<int> vecNums{ 1,2,3 };
std::array<int, 4> arrayNums{ 1,2,3,4 };
int cNums[6] = { 1,2,3,4,5,6 }; // c style

 

이와 같은 array들이 있다고할 때 하나씩 Print하기 위해서는 각 인터페이스에 맞는 함수를 만들어야한다.

// vector 출력
void printVec(std::vector<int> const& nums)
{
    for (int num : nums)
    {
        cout << num << endl;
    }
} 
// array 출력
void printArray(std::array<int> const& nums)
{
    for (int num : nums)
    {
        cout << num << endl;
    }
}

 

여기서 array는 vector와는 다른 타입이기 때문에 또 다른 인터페이스를 갖는 함수를 만들어야한다. 그런데 3개의 데이터 타입 모두 연속적인 공간에 데이터가 있다는 공통적인 특성이 있다. 이를 이용해 인터페이스를 만들면 하나의 함수로 모두 대응할 수 있다.


그것이 바로 C++ 20부터 추가된 std::span 이다. span의 내부정보에는 array의 시작 주소 정보와 사이즈 정보가 들어있다. 타입이 다른 array여도 시작점과 사이즈 정보만 알고 있으면 하나의 함수 인터페이스만으로도 대응 가능하다는 것이다.

void printSpan(std::span<int> nums)
{
    for (int num : nums)
    {
        cout << num << endl;
    }
}

int main()
{
	std::span<int> sp1(vecNums);
	std::span<int> sp2(arrayNums);
	std::span<int> sp3(cNums);
	printSpan(sp1);
	printSpan(sp2);
	printSpan(sp3);
}

 

span은 내부에 시작점과 사이즈 정보만 가지고 있기 때문에 Deep Copy를 해도 성능에 영향이 없다. 또한, find 같은 standard 알고리즘도 적용가능하다.

void findSpan(std::span<int> nums)
{
    auto ret = std::ranges::find(nums, 3); // 여기서 ranges는 C++ 20 부터 추가된 기능이다.
    if (ret != nums.end())
    {
        std::cout << "Found 3" << std::endl;
    }
}

 

주의 사항

span은 시작점과 사이즈만 알고 있기 때문에 만약 원본이 바뀌면 잘못된 데이터 공간에 접근하게 된다.

std::vector<int> nums{ 1,2,3 };
std::span<int> sp(nums);

nums.push_back(4);
printSpan(sp);

 

처음에 1,2,3이 들어있는 vector를 만들었다. 이후 4를 추가하면서 vector 메커니즘에 의해 새로운 공간에 마이그레이션이 되어 1,2,3,4 가 들어가게되고 기존의 메모리 공간은 의미 없는 공간이 된다. 그렇기 때문에 쓰레기 값이 출력되는 것이다. 즉, 원본이 바뀌었다면 조심해야한다.

 

span은 시작점과 사이즈를 알기 때문에 원본의 수정도 가능하다.

std::vector<int> nums{ 1,2,3 };
std::span<int> sp(nums);
sort(sp.begin(), sp.end()); // Sort가 된다.

 

이러한 원본 코드의 수정을 막기위해 const를 붙일 수 있는데 span은 const 를 앞에 붙이는 것이 아니라 내부 element를 유지하려면 다음과 같이 붙여줘야한다. span 그 자체를 유지할 때는 앞에 붙이면 된다. 

int main()
{
	std::vector<int> nums{ 1,2,3 };
	std::span<const int> sp(nums); // 내부 Element 유지
	const std::span<int> sp(nums); // span 그 자체 유지
}

 

span extent

span에는 2가지 모드가 있다.

  • dynamic_extent
  • static_extent

위에서 알아본 것은 default 값으로 지정된 dynamic_extent이다.

span의 사이즈를 컴파일 시간에 알 수 있다면 최적화가 가능할 것인데 그것이 static_extent이다.

 

static_extent는 내부에 시작점 정보만 가지고 있고, 사이즈는 데이터로 들어가는 것이 아니라 컴파일 시간에 그 숫자 자체로 들어가게 된다. 

int main()
{
	std::vector<int> nums{ 1,2,3 };
	std::span<int, 3> fixedSpan(nums);
}

 

컴파일러는 바이너리가 실행될 때 span의 사이즈를 매번 확인하지 않고 숫자가 지정되서 컴파일되므로 최적화가 될 수 있다. span은 subspan과 같은 유용한 기능들이 있으므로 cppreference를 참고하면 되겠다.

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

[C++] Perfect forwarding  (0) 2022.10.05
[C++] constexpr  (0) 2022.10.05
스마트 포인터 문제 - 순환 참조  (0) 2022.10.03
[C++] 문자열 정리  (0) 2022.09.29
[C++17] string_view  (0) 2022.09.07
    'C++/Modern C++' 카테고리의 다른 글
    • [C++] constexpr
    • 스마트 포인터 문제 - 순환 참조
    • [C++] 문자열 정리
    • [C++17] string_view
    CodeNote
    CodeNote
    기록 블로그

    티스토리툴바