Skip to Content

Tensor 수명과 RAII

실습복습
관련 기초 개념

개요

텐서 버퍼·세션·결과의 수명을 관리하고 잘못된 입력을 거절한다.

먼저 ONNX 모델과 입출력 계약의 핵심 개념을 확인하세요.

핵심 개요

C++ 추론에서 외부 버퍼를 참조하는 텐서는 실행이 끝날 때까지 해당 메모리가 유효해야 합니다. 텐서 래퍼의 수명과 버퍼 소유권은 같지 않을 수 있으므로 API의 복사·참조 계약을 확인합니다.

RAII는 객체의 수명과 자원 해제를 연결합니다. 세션·입력 이름·텐서·결과의 소유권을 타입으로 드러내고 비동기 작업이 지역 변수나 해제된 메모리를 참조하지 않게 합니다.

SDK에서 반환한 비소유 뷰의 부모 객체도 보관해야 합니다. 예를 들어 inputType=session.GetInputTypeInfo(0)를 변수로 유지한 뒤 inputType.GetTensorTypeAndShapeInfo()를 사용합니다. 임시 TypeInfo에서 얻은 뷰만 남기면 부모 해제 뒤 접근할 수 있습니다. C++ AI 통합 프로젝트 실행 예제는 이 소유 관계를 명시합니다.

필요한 용어

  • RAII: 객체 생성·소멸에 자원 획득·해제를 연결하는 C++ 방식
  • 비소유 뷰: 메모리를 소유하지 않고 외부 자료를 참조하는 표현

작동 과정

  1. 각 객체가 소유하는 자원과 참조를 표시합니다.
  2. 형상·원소 수·버퍼 수명을 검사합니다.
  3. 지역 버퍼 소멸·재할당·오류 경로를 시험합니다.

풀이 예제

아래 입력과 기록은 직접 만든 교육용 가상 자료입니다.

입력·조건

지역 vector의 data를 가리키는 텐서를 반환한 뒤 함수가 끝났습니다.

판단·결과

반환된 텐서가 버퍼를 복사하지 않았다면 수명이 끝난 메모리를 참조합니다.

이렇게 판단한 이유

래퍼 객체가 남아 있어도 참조 대상의 메모리가 유지된다는 보장은 없습니다.

로컬 실행 예제

실행 파일 받기

C++17, g++ -std=c++17 -Wall -Wextra -Werror tensor_lifetime.cpp -o tensor_lifetime 후 ./tensor_lifetime

g++ -std=c++17 -pthread -Wall -Wextra -Werror tensor_lifetime.cpp -o tensor_lifetime ./tensor_lifetime
// C++17: own data, validate dimensions, reject overflow before making a view. #include <cassert> #include <cstdint> #include <iostream> #include <limits> #include <stdexcept> #include <vector> std::size_t elements(const std::vector<int64_t>& shape) { std::size_t n = 1; for (auto dimension : shape) { if (dimension <= 0 || static_cast<uint64_t>(dimension) > std::numeric_limits<std::size_t>::max()/n) throw std::invalid_argument("invalid shape"); n *= static_cast<std::size_t>(dimension); } return n; } struct Input { std::vector<int64_t> shape; std::vector<float> buffer; Input(std::vector<int64_t> s, std::vector<float> b):shape(std::move(s)),buffer(std::move(b)) { if (elements(shape) != buffer.size()) throw std::invalid_argument("element count mismatch"); } }; int main() { const Input input({1,3},{1,2,3}); // No reallocation or mutation while a tensor borrows buffer. assert(input.buffer.size()==3 && input.buffer[2]==3); bool bad = false; try { Input invalid({2,3},{1,2,3}); } catch(const std::invalid_argument&) { bad=true; } assert(bad); bad=false; try { elements({INT64_MAX,INT64_MAX}); } catch(const std::invalid_argument&) { bad=true; } assert(bad); std::cout << "PASS: owned input, shape mismatch and overflow rejection\n"; }

기대 결과: 소유 입력·원소 수 불일치·형상 곱 오버플로 거절

2026-10-21 로컬 환경에서 실행했습니다. 가상 자료·소형 CPU 예제의 동작 검사이며 실제 업무 모델의 품질·클라우드·GPU·Office 제품 연동 검증은 아닙니다.

흔한 실패와 복구

raw pointer가 유효한지 값만 보고 판단하지 않습니다. 수명·소유권·재할당 경로를 코드 구조로 보장합니다.

확인 문제

외부 버퍼 참조 텐서에서 반드시 유지할 것은?

  1. 실행이 참조하는 동안의 버퍼 수명과 주소 안정성
  2. 텐서 변수 이름만
  3. 버퍼가 있던 함수의 주석만

풀이 기록 기능을 불러오는 중…

해설 보기

정답: A. 실행이 참조하는 동안의 버퍼 수명과 주소 안정성

실행이 참조하는 동안의 버퍼 수명과 주소 안정성 raw pointer가 유효한지 값만 보고 판단하지 않습니다. 수명·소유권·재할당 경로를 코드 구조로 보장합니다.

참고 자료

  1. ONNX Runtime: Ort::Session  — 세션 생성·입출력 정보·실행 계약.
  2. ONNX Runtime: C++  — C++ API와 모델 추론 진입점.

자료 확인: 2026-10-21. 사례·문항·실습은 자체 제작했습니다. 외부 서비스 호출과 실제 모델 품질 측정은 학습자가 별도 환경에서 수행합니다.

직접 적용하기

교육용 가상 상황

비동기 추론에 넘길 입력 버퍼와 세션의 소유권을 설계하고 재할당·예외·반환 결과의 수명을 검사하세요.

텐서 버퍼·세션·결과의 수명을 관리하고 잘못된 입력을 거절한다. 판단 근거와 검증할 결과를 적으세요.

답안 저장 기능을 불러오는 중…

검증 기준과 해설 보기
  1. 실행 완료까지 버퍼·세션을 유지한다
  2. 뷰와 소유 객체를 구분한다
  3. 형상·타입·수명·예외 경로를 검증한다

작업 객체가 입력 vector와 필요한 세션 수명을 소유하도록 합니다. 텐서 생성 뒤 버퍼를 재할당하거나 지역 참조를 넘기지 않습니다. 실행 결과는 반환 객체의 수명 안에서 읽거나 명시적으로 복사합니다. 형상 곱·타입·오류·예외 후 자원 해제를 검사합니다.

복습하기

  1. RAII는 무엇을 연결하나요?
  2. 뷰가 버퍼를 소유하나요?
  3. vector 재할당이 위험한 이유는?
답변 확인 기준
  1. RAII는 무엇을 연결하나요?

    객체 수명과 자원 획득·해제를 연결합니다.

  2. 뷰가 버퍼를 소유하나요?

    계약에 따라 다르며 비소유 뷰는 소유하지 않습니다.

  3. vector 재할당이 위험한 이유는?

    기존 data 포인터의 주소 유효성이 깨질 수 있기 때문입니다.