Huny's Dev Blog
huny.dev

C++ string_view를 저장했는데 문자열이 바뀔 때: 작업 큐의 소유권과 수명 관리

string_view는 문자열 사본이 아니다. C++17의 6개 실행 검사로 원본 수정·부분 뷰·널 종료를 구분하고, 작업 큐에 string을 복사해 안전하게 보관하는 경계를 확인한다.

Hun Jang
Hun Jang Nov 6, 2026

C++에서 std::string_view를 작업 큐나 멤버에 저장한 뒤 내용이 달라진다면, 원본 버퍼의 소유자와 수명부터 확인한다. 뷰는 문자열의 복사본이 아니다. 호출 이후에도 값을 보존해야 하는 작업은 원본이 유효할 때 std::string으로 복사해 소유한다. C++17 예제로 원본 변경, 부분 뷰, 널 종료와 큐 저장의 차이를 확인한다.

공유 메모리를 들여다보는 창과 별도로 보관한 사본을 표현한 개념 일러스트다. 실제 메모리 배치도는 아니다.

작성·문서 확인: 2026-11-06. 실행 검증: Linux, GCC 14.2.0, C++17. 합성 예제의 기능 검사이며 사용자 SDK나 실제 TTS 엔진을 시험한 결과는 아니다.

읽기 전용 뷰가 원본을 불변으로 만들지는 않는다

Microsoft의 string_view 설명은 이를 문자 데이터를 소유하지 않는 읽기 전용 핸들로 소개한다. 뷰를 통해 수정할 수 없다는 뜻이지, 다른 경로로 원본을 바꿀 수 없다는 뜻은 아니다.

예제에서는 owner[0]만 수정한다. 길이를 바꾸거나 재할당하지 않아도 뷰에서 읽는 내용은 alpha에서 Alpha로 달라진다. 반면 변경 전에 만든 std::string snapshot(view)는 이전 값을 유지한다. “주소가 그대로니까 값도 보존된다”는 판단이 틀리는 사례다.

더 위험한 경우는 원본의 소멸이나 포인터 무효화다. C++ 작업 초안의 string.view.template.general은 참조 대상 포인터를 무효화하는 연산과 뷰의 관계를 명시한다. 임시 문자열이나 지역 문자열을 가리키는 뷰를 반환·저장해도 원본의 수명이 늘어나지 않는다. 이때 뷰를 읽으면 정의되지 않은 동작이 될 수 있다. 초안은 변경 가능한 문서이며, 아래 코드는 C++17에 있는 기능만 사용한다.

보관 경계에서 소유하는 문자열로 복사한다

예제의 enqueue는 입력을 잠시 읽기 위해 string_view를 받고, 큐 안에는 string을 저장한다. 입력을 빌리는 인터페이스와 결과를 소유하는 저장소를 구분한 것이다. 복사는 입력이 아직 유효한 동안 이루어져야 한다. 이미 수명이 끝난 뷰를 string으로 바꾼다고 복구되지는 않는다.

아래를 string_view_demo.cpp로 저장한다. 큐는 소유권 설명용 vector이며 동시 접근을 지원하는 작업 큐 구현은 아니다.

검증에 사용한 명령이다. assert 검사를 유지하도록 NDEBUG를 정의하지 않는다.

실행 결과는 다음과 같다.

여섯 검사에서 확인한 경계

검사
확인한 사실
적용 시 판단
1. 뷰 생성
data가 원본 주소와 같다
문자 데이터의 사본이 아니다
2. 원본 문자 수정
주소는 같고 뷰의 값은 바뀐다
수명뿐 아니라 변경 시점도 관리한다
3. 소유한 사본
이전 alpha를 유지한다
스냅샷이 필요하면 복사한다
4. view.substr
원본의 중간 주소를 계속 참조한다
부분 뷰도 원본에 의존한다
5. 포인터와 길이
ab 범위 뒤의 실제 배열 원소는 c다
널 종료 C 문자열과 구분한다
6. 큐의 string
원본 수정·지역 범위 종료 후 값이 유지된다
나중에 실행할 작업이 데이터를 소유하게 한다

5번은 배열 범위 안의 raw[2]를 검사한다. 뷰 범위를 벗어난 prefix[2]를 읽지 않는다. data()만 C 문자열 함수에 넘기는 것도 시험하지 않는다. 초안의 data 설명은 널 종료를 보장하지 않는다는 점을 경고한다. 널 종료가 필요한 호출에는 예제처럼 소유한 string을 만들고, 그 string이 유효한 동안 c_str()을 사용한다. 호출 대상이 포인터를 보관한다면 그 이후 수명도 별도로 보장해야 한다.

수명·변경·동시성을 따로 확인한다

원본이 살아 있고, 참조 구간이 유효하며, 사용 중 안전하게 읽을 수 있는 동기 처리에는 뷰가 적합할 수 있다. 나중에 실행할 콜백, 이벤트 큐, 캐시처럼 보관 기간이 길어지는 지점에서는 소유권을 명시한다. 뷰 객체 자체를 값으로 복사하거나 const로 선언해도 원본 데이터의 복사본은 생기지 않는다.

이 검증에서는 수명이 끝난 메모리를 일부러 읽거나 재할당 뒤의 뷰를 역참조하지 않았다. 그런 잘못된 코드가 우연히 정상 출력된다고 안전성을 판단할 수 없기 때문이다. 스레드·메모리 할당 실패·처리량·복사 비용도 측정하지 않았다. 실제 적용에서는 큐가 입력을 언제 복사하는지, 생산자가 버퍼를 언제 재사용하는지, C API가 포인터를 호출 이후에도 보관하는지 확인한다. 다른 스레드가 원본을 쓰는 경우에는 수명 보장과 별개로 동기화도 필요하다.

English version: C++ string_view Lifetime: Preserve Queued Text with Owning StringsC++ string_view Lifetime: Preserve Queued Text with Owning Strings

추천 글