/

|

std::span은 연속된 원소를 소유하지 않고 가리키는 C++20 뷰이며, 배열이나 컨테이너를 복사 없이 함수에 넘길 때 씁니다.

이 글은 cppreference의 span 문서를 2026-08-30 기준으로 정리한 일반 설명이며, 표준 버전과 구현에 따라 세부 동작은 달라질 수 있습니다.

std::span은 무엇입니까?

한 줄 답: 이 타입은 연속된 원소 시퀀스를 소유하지 않고 가리키는 C++20 뷰입니다.

이 타입은 <span> 헤더에 정의된 C++20 클래스 템플릿이며, 기본 Extentstd::dynamic_extent입니다. 연속된 객체 시퀀스를 가리키고, 그 시퀀스의 첫 원소가 위치 0에 있는 구조를 표현합니다.

정적 extent에서는 원소 수가 컴파일 타임에 알려지고 타입에 인코딩됩니다. 동적 extent에서는 원소 수가 실행 중 범위 정보로 표현되므로, 고정된 길이를 타입으로 나타낼지 실행 중 길이로 다룰지를 구분할 수 있습니다. 이 뷰는 메모리를 소유하지 않습니다.

포인터와 길이 쌍과 무엇이 다릅니까?

한 줄 답: 이 뷰는 시작 포인터와 길이를 타입·멤버로 묶고, 정적 extent는 길이를 타입에 인코딩합니다.

T*와 원소 수를 별도 인자로 전달하는 방식에서는 포인터와 범위 정보가 호출 규약에 나뉘어 있습니다. 이 방식에서는 data()로 기반 연속 저장소의 시작 포인터를 얻고 size()로 원소 수를 관찰하므로, 범위를 나타내는 정보가 하나의 뷰에 함께 표현됩니다.

extent는 템플릿의 extent를 나타내는 정적 멤버 상수이고, std::dynamic_extent는 정적 extent와 동적 extent를 구분하는 헬퍼 상수입니다. 문서의 exposition 설명에서는 정적 extent 값과 기반 저장소 포인터가 나타나며, 동적 extent일 때만 실행 중 크기를 보관하는 size_가 함께 나타납니다.

연속된 일부만 다룰 때는 first, last, subspan으로 부분 뷰를 얻을 수 있습니다. subspan은 offset과 count로 연속된 원소의 일부를 정하므로, 포인터를 잘라낸 뒤 길이를 별도로 다시 관리하는 형태보다 범위의 의미를 뚜렷하게 나타냅니다.

함수 인자로는 어떻게 씁니까?

한 줄 답: 연속 저장소를 이 뷰 매개변수로 받으면 배열이나 컨테이너를 복사하지 않고 범위를 넘깁니다.

읽기 전용 접근이 목적이라면 원소 타입에 const를 붙인 매개변수를 사용할 수 있습니다. 다음처럼 함수가 범위를 값으로 받으면 함수 안에서 size(), data(), subspan을 통해 전달된 연속 범위를 관찰할 수 있습니다.

#include <span>

void display(std::span<const char> abc) {
    // abc.size(), abc.data(), abc.subspan(...)
}

이 뷰를 값으로 전달하는 것은 뷰가 가진 범위 정보를 전달하는 일이며, 기반 배열이나 컨테이너의 원소를 복사하는 방식이 아닙니다. 공식 예시에서는 C 배열과 std::array를 통해 정적 extent를 얻고, std::vector를 통해 동적 extent를 다루는 형태를 보여 줍니다.

다만 여기서 전제하는 대상은 연속 저장소를 제공하는 시퀀스입니다. 컨테이너라는 이유만으로 모든 종류를 같은 방식으로 넘길 수 있다고 일반화하지 않고, 실제로 연속된 원소를 가진 범위인지 확인해야 합니다.

수명과 소유권에서 주의할 점은 무엇입니까?

한 줄 답: 이 뷰는 원본 시퀀스의 수명에 의존하며, 원본의 포인터가 무효화되면 이 뷰의 원소 접근도 무효화됩니다.

원본 배열의 수명이 끝나거나 기반 컨테이너가 파괴되면, 이 뷰가 가리킬 원소도 더 이상 유효한 저장소에 남아 있지 않습니다. 또한 [s.data(), s.data() + s.size()) 범위의 포인터를 무효화하는 연산이 원본에 일어나면, 해당 범위 원소에 대한 포인터·반복자·참조도 무효화됩니다.

따라서 지역 배열이 유효한 범위를 벗어난 뒤 뷰를 보관하거나, 원본 컨테이너를 파괴한 뒤 남은 뷰에 접근해서는 안 됩니다. 원본을 이동한 뒤의 상태에 의존하는 뷰를 남기지 않는 것도 같은 수명 규칙을 지키는 방법입니다.

이 타입에는 std::ranges::enable_borrowed_rangestd::ranges::enable_view가 적용되어 borrowed_rangeview를 만족한다는 특성도 있습니다.

FAQ

한 줄 답: C++20 여부, extent의 형태, 그리고 원본 저장소가 유효한지를 차례로 확인하면 됩니다.

질문 답변
C++ 몇 표준부터 쓸 수 있습니까? C++20부터 사용할 수 있습니다.
정적 extent와 동적 extent는 무엇입니까? 정적 extent는 원소 수가 컴파일 타임에 알려져 타입에 인코딩됩니다. 동적 extent는 std::dynamic_extent로 표현하며, 실제 원소 수는 실행 중 범위 정보로 다룹니다.
원본 배열이나 컨테이너가 사라지면 어떻게 됩니까? 이 뷰는 원본을 소유하지 않으므로, 원본 포인터가 무효화되면 원소 포인터·반복자·참조도 무효화됩니다. 원본 수명이 끝난 뒤에는 뷰를 사용해서는 안 됩니다.
모든 컨테이너를 넘길 수 있습니까? 이 글에서 다루는 대상은 연속 시퀀스입니다. 공식 예시는 C 배열, std::array, std::vector를 다루므로 컨테이너라는 이유만으로 모든 종류를 지원한다고 일반화할 수 없습니다.

출처

한 줄 답: 본문 사실과 짧은 코드 형태는 2026-08-30 기준으로 확인한 cppreference 문서만 사용합니다.

  • span — 클래스 템플릿 정의, extent, 무효화 규칙, 범위 특성, 함수 인자 예시를 확인했습니다.
  • dynamic_extent — 정적·동적 extent 구분과 비소유 뷰 설명을 확인했습니다.
  • span::size — 뷰의 원소 수를 반환하는 관찰자를 확인했습니다.
  • span::data — 기반 연속 저장소의 시작 포인터를 반환하는 관찰자를 확인했습니다.
  • span::subspan — offset과 count로 연속된 부분 뷰를 얻는 기능을 확인했습니다.

std::span is a non-owning C++20 view for contiguous elements. It allows you to pass arrays or containers to functions without copying the underlying data.

This article is a general guide based on the cppreference span documentation, reviewed on 2026-08-30. Specific behaviors may vary depending on your standard version and compiler implementation.

What is C++ std::span?

Short answer: std::span is a C++20 feature that acts as a lightweight, non-owning view over a contiguous sequence of elements.

Defined in the <span> header, this C++20 class template defaults to std::dynamic_extent. It represents a contiguous block of objects, where the first element is located at index 0.

A static extent encodes the number of elements directly into the type at compile time. In contrast, a dynamic extent handles the element count as runtime information. This allows developers to choose between fixed-length type safety and runtime flexibility, all while the view itself never owns or allocates memory.

How is C++ std::span different from a pointer and length pair?

Short answer: It encapsulates the starting pointer and the length into a single, cohesive view type, rather than splitting them across function arguments.

Traditionally, passing a T* pointer and a size argument separates range data across a function's calling convention. std::span resolves this by combining the start pointer of the underlying contiguous storage (via data()) and the element count (via size()) into one object.

The extent static data member represents the template's capacity, while std::dynamic_extent is a helper constant used to differentiate static from dynamic spans. In the standard's exposition, a static extent span only stores a pointer, whereas a dynamic extent span stores both the pointer and a runtime size_.

For working with subsets of data, methods like first, last, and subspan generate subviews. By taking an offset and a count, subspan clearly communicates the intent to slice a range, which is much safer and more readable than performing manual pointer arithmetic.

How do you use C++ std::span as a function parameter?

Short answer: Pass it by value to safely and efficiently provide functions with range data without copying the actual array or container.

If the function only needs read-only access, use a const element type in the template parameter. When a function takes this view by value, it can inspect the continuous range using size(), data(), and subspan.

#include <span>

void display(std::span<const char> abc) {
    // abc.size(), abc.data(), abc.subspan(...)
}

Passing by value only copies the view's internal pointer and size, never the underlying elements. Official examples demonstrate using C-style arrays and std::array to create static extents, while std::vector is commonly used for dynamic extents.

Keep in mind that the source must provide contiguous storage. You cannot pass just any container type; always verify that the underlying data structure stores its elements contiguously in memory.

What should you watch for with C++ std::span lifetime and ownership?

Short answer: Because it does not own the data, a span becomes invalid the moment its underlying sequence is destroyed or reallocated.

If the original array goes out of scope or the backing container is destroyed, the view points to invalid memory. Furthermore, if an operation on the source container invalidates pointers within the [s.data(), s.data() + s.size()) range, all pointers, iterators, and references held by the view are also invalidated.

Never store a view of a local array after it exits its scope, and do not access a view after its source container has been destroyed or moved. Views that depend on moved-from sources follow the same strict lifetime rules.

Additionally, the type satisfies both borrowed_range and view concepts, as it implements std::ranges::enable_borrowed_range and std::ranges::enable_view.

What are the common C++ std::span FAQs?

Short answer: Most questions revolve around C++20 compatibility, the difference between static and dynamic extents, and safely managing the underlying storage lifetime.

Question Answer
Which C++ standard introduced std::span? It is available starting with C++20.
What is the difference between static and dynamic extents? A static extent has its element count fixed at compile time and encoded in the type. A dynamic extent uses std::dynamic_extent to manage the element count at runtime.
What happens if the original container disappears? Because the view is non-owning, any iterators or references become dangling if the source is destroyed or reallocated. Do not use the view after the original data's lifetime ends.
Can you pass any C++ container to a span? No, it only supports contiguous sequences. While C arrays, std::array, and std::vector work perfectly, non-contiguous containers like std::list or std::map are not supported.

Which sources support this C++ std::span guide?

Short answer: The facts, terminology, and code structure in this article are based directly on the official cppreference documentation, reviewed on 2026-08-30.

  • span — Verified the class template definition, extent types, iterator invalidation rules, range concepts, and parameter examples.
  • dynamic_extent — Verified the distinction between static and dynamic extents.
  • span::size — Verified the observer method that returns the element count.
  • span::data — Verified the observer method that returns the pointer to the underlying data.
  • span::subspan — Verified the method for extracting contiguous subviews.

+ Recent posts