-
[SE-0524] Add withTemporaryAllocation using Output(Raw)SpanSwift 2026. 5. 9. 13:50
안녕하세요. 그린입니다 🍏
이번 포스팅에서는 SE-0524 — OutputSpan을 활용한 withTemporaryAllocation 추가에 대해 정리해보겠습니다 🙋🏻

Intro
- Proposal: SE-0524
- Author: Max Desiatov
- Review Manager: Doug Gregor
- Status: Implemented (Swift 6.4)
Motivation
SE-0322와 SE-0437에서 도입된
withUnsafeTemporaryAllocation은 스택에 임시 메모리를 할당할 수 있는 유용한 API입니다.하지만 이 함수는
UnsafeMutableBufferPointer또는UnsafeMutableRawBufferPointer를 yield하기 때문에, 초기화와 해제를 개발자가 직접 관리해야 했어요.// 기존 방식 — 수동 관리가 필요해서 실수하기 쉬워요 🐛 withUnsafeTemporaryAllocation(of: Float.self, capacity: 42) { buffer in // 초기화, 사용, 해제를 모두 직접 해야 함 // 에러 발생 시 deinit을 빠뜨리면 버그로 이어짐 }에러가 발생하는 경우에도 초기화된 요소를 올바르게 해제해야 한다는 점이 특히 까다로웠습니다.
한편, SE-0485에서 도입된
OutputSpan과OutputRawSpan은 연속적인 메모리 영역의 초기화 상태를 직접 추적하고 관리해주는 타입입니다.이 두 가지를 결합하면? 안전하고 편리한 임시 메모리 할당 API를 만들 수 있습니다!
Proposed Solution
withUnsafeTemporaryAllocation을 내부적으로 감싸는 새로운 전역 함수 두 가지를 추가합니다.raw 포인터 대신
inout OutputSpan또는inout OutputRawSpan을 yield하는 방식이에요.타입 지정 할당 (Typed Allocation)
let capacity = 42 let result = try withTemporaryAllocation( of: Float.self, capacity: capacity ) { output -> Int in for i in 0..<capacity { output.append(i) } var mutableSpan = output.mutableSpan updateInPlace(&mutableSpan) return aggregate(output.span) // 클로저가 끝나면 OutputSpan이 자동으로 해제됩니다 }Raw 바이트 할당 (Raw Bytes Allocation)
let byteCount = 16 let result = try withTemporaryAllocation( byteCount: byteCount, alignment: 4 ) { rawSpan -> Int in rawSpan.append(repeating: 0, count: byteCount, as: UInt8.self) var mutableBytes = rawSpan.mutableBytes updateInPlace(&mutableBytes) return aggregate(rawSpan.bytes) // OutputRawSpan은 클로저 종료 시 자동으로 해제됩니다 }
Detailed Design
두 함수의 시그니처와 내부 동작을 살펴볼게요~
① withTemporaryAllocation(of:capacity:) — OutputSpan
@available(SwiftCompatibilitySpan 5.0, *) @export(implementation) public func withTemporaryAllocation<T: ~Copyable, R: ~Copyable, E: Error>( of type: T.Type, capacity: Int, _ body: (inout OutputSpan<T>) throws(E) -> R ) throws(E) -> R where T: ~Copyable, R: ~Copyable { try withUnsafeTemporaryAllocation(of: type, capacity: capacity) { (buffer) throws(E) in var span = OutputSpan(buffer: buffer, initializedCount: 0) defer { let initializedCount = span.finalize(for: buffer) span = OutputSpan() buffer.extracting(.<initializedCount).deinitialize() } return try body(&span) } }내부 동작 흐름은 다음과 같습니다.
- Allocation —
withUnsafeTemporaryAllocation(of:capacity:)로 초기화되지 않은 타입 버퍼를 확보합니다. - Span Creation —
initializedCount: 0으로OutputSpan을 생성합니다. - Execution —
OutputSpan을inout파라미터로 클로저에 전달합니다. - Cleanup —
defer블록에서finalize(for:)로 초기화된 요소 수를 파악하고,deinitialize()로 정리합니다.
② withTemporaryAllocation(byteCount:alignment:) — OutputRawSpan
@available(SwiftCompatibilitySpan 5.0, *) @export(implementation) public func withTemporaryAllocation<R: ~Copyable, E: Error>( byteCount: Int, alignment: Int, _ body: (inout OutputRawSpan) throws(E) -> R ) throws(E) -> R where R: ~Copyable { try withUnsafeTemporaryAllocation(byteCount: byteCount, alignment: alignment) { (buffer) throws(E) in var span = OutputRawSpan(buffer: buffer, initializedCount: 0) defer { _ = span.finalize(for: buffer) span = OutputRawSpan() } return try body(&span) } }OutputRawSpan은 raw 바이트를 다루며BitwiseCopyable로 간주되기 때문에,OutputSpan과 달리deinitialize()호출이 필요 없습니다.
임시 메모리는 자동으로 해제됩니다.
Source Compatibility / ABI
- 이번 변경은 순수 additive 변경으로, 기존 코드에 영향을 주지 않습니다.
- 두 함수 모두
@export(implementation)으로 표시되어 클라이언트 바이너리에 직접 인라인됩니다. - 표준 라이브러리의 새로운 ABI 엔트리 포인트가 아닌, 기존 ABI를 활용하는 방식이라 ABI 호환성에도 영향이 없습니다.
Alternatives Considered
아무것도 하지 않기
기존
withUnsafe...변형을 계속 사용하고 개발자가 직접OutputSpan/OutputRawSpan으로 감싸는 방법이 있어요.
하지만 동일한 보일러플레이트 코드를 반복해야 하기 때문에, 이번 제안처럼 표준 라이브러리에서 제공하는 것이 적절하다고 판단했습니다.OutputSpan / OutputRawSpan의 static 메서드로 추가하기
각 span 타입의 static 메서드로 만드는 방법도 고려되었지만,
withUnsafeTemporaryAllocation이나withExtendedLifetime같은 기존 전역 함수 패턴과 일관성을 유지하기 위해 전역 함수로 채택했습니다.
Future Directions
현재 제안은 주요 안전 래퍼를 다루고 있으며, 향후
async오버로드도 고려할 수 있어요.다만
async오버로드는 이 함수만을 위한 게 아니라 표준 라이브러리의with스타일 함수 전체에 걸쳐 일관되게 추가되어야 한다고 보고 있습니다.
또한 suspension point에서의 할당은 힙 메모리를 사용하게 되어, 스택 할당의 이점이 사라진다는 점도 고려 중이에요.
Conclusion
withUnsafeTemporaryAllocation과OutputSpan/OutputRawSpan의 강점을 결합한 실용적인 변경입니다 🙌기존에는 임시 메모리 할당 시 raw 포인터를 직접 다루며 초기화/해제 관리까지 책임져야 했는데, 이번 제안으로 안전하고 간결하게 임시 메모리를 사용할 수 있게 됩니다.
특히 unsafe API에 익숙하지 않은 개발자도 스택 할당 임시 메모리를 부담 없이 활용할 수 있게 된다는 점에서 진입 장벽을 낮추는 변경이라고 생각합니다 😄
References
swift-evolution/proposals/0524-span-temporary-allocation.md at main · swiftlang/swift-evolution
This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution
github.com
'Swift' 카테고리의 다른 글
[SE-0522] Source-Level Control Over Compiler Warnings (0) 2026.05.23 [SE-0523] Hashable conformance for UnownedTaskExecutor (1) 2026.05.15 [SE-0521] Improved Syntax for Optionals of Opaque and Existential Types (0) 2026.05.01 [SE-0520] Discardable result use in Task initializers (0) 2026.04.25 [SE-0519] Borrow and Inout types for safe, first-class references (2) 2026.04.11