Post

2026-03-16 TIL (15일차)

2026-03-16 TIL (15일차)

C++


💡 [Tip] 벡터의 reserve(size_t _Newcapacity)

● vector의 현재 capacity를 수정합니다.
● _Newcapacity가 기존 capacity보다 작은 경우(_Newcapacity < capacity)에는 아무 일도 발생하지 않습니다.
● _Newcapacity가 기존 capacity보다 큰 경우(capacity < _Newcapacity)에는 메모리 재할당이 발생합니다.
● 단, 값 초기화는 해주지 않고 그대로 복사해서 이사를 한다.


💡 [Tip] reserve vs resize 비교

구분reserve(n)resize(n)
주 목적용량(Capacity) 미리 확보크기(Size) 변경 (실제 데이터 개수)
작은 값 입력 시무시함 (변화 없음)데이터 삭제 (n번째 이후 요소 파괴)
메모리 이사설정값이 용량보다 클 때만 발생설정값이 용량보다 클 때 발생 가능
접근 오류크기 변화가 없어 영향 없음삭제된 인덱스 접근 시 오류(Crash)



4번 과제 재료 검색기능

📋 수도 코드

  1. 결과 저장소 준비: 검색된 레시피들을 담을 빈 벡터를 생성합니다.
  2. 전체 순회: 전체 recipes 벡터를 처음부터 끝까지 하나씩 확인합니다.
  3. 데이터 접근: 현재 확인 중인 레시피의 ‘재료 목록’을 가져옵니다.
    • 3-1. 대조: 입력받은 이름과 일치하는 재료가 있는지 내부 루프를 통해 확인합니다.
  4. 조건부 저장: 일치하는 재료를 찾았다면 해당 레시피를 결과 벡터에 저장하고, 중복 방지를 위해 즉시 다음 레시피로 넘어갑니다.
  5. 결과 반환: 모든 순회가 끝나면 레시피가 담긴 벡터를 최종 반환합니다.
  6. 결과 출력: 반환받은 벡터가 비어있지 않다면, 반복문을 돌려 찾은 레시피들의 이름을 모두 출력한다.



🚨 버그 리포트1: 공백 입력 이슈

레시피 추가 기능에서 아무 내용 없이 엔터만 입력해도 이름 없는 물약과 재료가 추가되는 오류를 발견했습니다.

발생 현상

  • 물약 이름 입력 단계에서 엔터 입력 시 빈 문자열("")이 이름으로 저장됨
  • 재료 입력 시에도 동일하게 공백 데이터가 리스트에 추가됨

과제 오류

🔍 원인 분석

이 문제는 std::getline() 함수의 작동 방식 때문에 발생합니다.

getline(cin, string)\n(개행 문자)을 구분자로 사용하여 문자열을 읽어 들입니다.
● 사용자가 엔터를 누르면 버퍼에서 \n을 찾아 읽은 뒤 이를 지우지만, 그 사이에 아무 텍스트가 없다면 빈 문자열로 간주합니다.

✅ 해결 방법 입력받은 문자열이 비어있는지(.empty()) 확인하고, 공백일 경우 경고 메시지와 함께 입력을 다시 받도록 예외 처리를 추가했습니다.

1
2
3
4
if (문자열.empty()) {
    std::cout << ">> 잘못된 입력입니다. 물약 이름을 입력해주세요." << std::endl;
    continue; // 2. 루프의 처음으로 돌아가 다시 입력을 받음
}



🚨 버그 리포트2: 레시피 중복 출력 이슈

재료 검색 기능 실행 시, 하나의 레시피 내에 동일한 재료가 여러 개 포함되어 있으면 검색 결과에 해당 레시피가 중복되어 출력되는 현상을 발견했습니다.

과제 오류

🔍 원인 분석
내부 루프에서 일치하는 재료를 찾은 뒤에도 루프를 중단하지 않고 나머지 재료들을 계속 대조하기 때문에, 일치하는 개수만큼 push_back이 호출되는 것이 원인이었습니다.

1
2
3
4
5
6
7
// 문제의 코드
for (int j = 0; j < recipes[i].Getingredients().size(); j++) {
    if (recipes[i].Getingredients()[j] == name) {
        Ingerdient_Results.push_back(&recipes[i]); 
        // 여기서 멈추지 않고 끝까지 검사함 -> 중복 발생!
    }
}

✅ 해결 방법
break 예약어를 사용하여 일치하는 재료를 단 하나라도 찾았다면 내부 루프를 탈출하게 수정하였습니다.

1
2
3
4
5
6
for (int j = 0; j < recipes[i].Getingredients().size(); j++) {
    if (recipes[i].Getingredients()[j] == name) {
        Ingerdient_Results.push_back(&recipes[i]);
+       break; // ✅ 일치하는 레시피를 찾았으므로 더 이상의 재료 검사는 생략
    }
}



⚠️ 주의: 벡터의 메모리 재할당과 주소 무효화

vectorpush_back으로 요소를 추가하다가 더 큰 공간이 필요해지면, 새로운 메모리 블록을 할당받아 기존 요소들을 통째로 이사 시킵니다.
즉, 큰 공간으로 할당받기전에 있던 주소는 해제하고 새로운 주소로 간다는 이야기이다.

🚨 메모리 참조 오류 발생 원인
● 만약 복사비용을 아낄려고 벡터의 값의 하나하나 주소만 받아서 접근해서 사용하던중 벡터가 capacity가 증가하게되면 벡터 값들의 주소가 변경
● 증가하기 전의 벡터 주소값을 저장한 변수를 바로 갱신하지 않고 값을 읽거나 쓰려고 하면, 예전 주소로 접근하여 메모리 참조 오류가 발생




Unreal 기초

Tip 1

언리얼 엔진 5에서 C++ 코드를 실시간으로 반영해 주는 라이브 코딩은 편리하지만, 많은 숙련된 개발자들은 안정적인 개발을 위해 이 기능을 해제(Disable)할 것을 권장합니다.

⚠️ 라이브 코딩 사용 시 발생하는 주요 문제점

● 헤더 파일(.h) 수정의 한계
라이브 코딩은 주로 .cpp 파일의 로직 수정에 최적화되어 있습니다.

  • 위험: 새로운 변수를 추가하거나 함수 이름을 바꾸는 등 헤더 구조를 변경할 때 엔진이 이를 제대로 인식하지 못하는 경우가 빈번합니다.
  • 결과: 에디터 크래시(Crash)가 나거나 블루프린트 데이터가 꼬이는 원인이 됩니다.

● “유령 버그”의 발생
코드는 논리적으로 완벽한데 엔진에서 이상하게 작동하는 현상이 발생합니다.

  • 위험: 발생한 버그가 내 로직 문제인지, 아니면 라이브 코딩의 반영 오류(Hot Reload 실패 등)인지 헷갈리게 됩니다.
  • 결과: 결국 에디터를 재시작해야 해결되는 경우가 많아 오히려 디버깅 시간을 낭비하게 됩니다.

● 빌드 주도권 및 프로세스 혼선
라이브 코딩이 켜져 있으면 비주얼 스튜디오(Visual Studio)와의 동기화가 복잡해집니다.

  • 위험: VS에서 ‘빌드’를 눌렀을 때 에러가 나거나, 라이브 코딩 전용 창이 별도로 뜨면서 빌드 프로세스가 이원화됩니다.
  • 결과: 빌드가 정확히 어디서 수행되고 있는지 혼란을 초래할 수 있습니다.

● 컴파일 결과의 휘발성
라이브 코딩으로 컴파일된 결과는 ‘패치’ 형태로 임시 적용됩니다.

  • 위험: 확실하게 바이너리 파일에 기록되는 일반 빌드보다 신뢰도가 낮습니다.
  • 결과: 에디터를 완전히 껐다 켜면 다시 컴파일해야 하는 등 데이터 보존성이 떨어집니다.



Tip 2

Visual Studio 단축키 요약 (에디터 실행 중 기준)

개발 중 에디터가 켜져 있는 상태에서 비주얼 스튜디오 단축키를 누르면 어떻게 작동하는지 정리한 표입니다.

단축키에디터 실행 중 입력 시 결과한 줄 요약
F5창이 하나 더 뜨며 중복 실행됨 (메모리 점유율 상승)실행 (디버깅 시작)
Shift + F5실행 중이던 에디터 창이 즉시 닫힘실행 중단 (종료)
Ctrl + Shift + F5에디터 종료 후, 재빌드를 거쳐 새 창이 실행됨재시작 (업데이트)
Ctrl + Shift + B에디터가 파일을 점유 중이라 빌드 오류 발생 확률 높음프로젝트 빌드 (컴파일)



Tip 3

상황별 컴파일

● 에디터가 켜져 있을 때 (단순 로직 수정) .cpp 파일 내의 수치나 간단한 실행 로직만 변경하는 경우입니다.

  1. 코드 수정: 비주얼 스튜디오에서 코드를 수정한 후 저장(Ctrl + S)합니다.
  2. 컴파일 실행: 언리얼 에디터로 돌아와 하단의 컴파일 버튼(핫 리로드/라이브 코딩)을 클릭하여 즉시 반영합니다.

● 헤더(.h) 수정 및 클래스 추가 시 (구조 변경) 변수 추가, 함수 선언 변경, 혹은 새로운 클래스를 생성했을 때의 정석 루트입니다.

  1. 에디터 종료: Shift + F5를 눌러 실행 중인 에디터를 즉시 종료합니다.
  2. 프로젝트 빌드: 비주얼 스튜디오에서 Ctrl + Shift + B를 눌러 전체 프로젝트를 빌드합니다.
  3. 디버깅 실행: 빌드가 완료되면 F5를 눌러 다시 에디터를 실행합니다.

⚠️ 주의사항: 핫 리로드(Hot Reload)와 데이터 오염 에디터가 켜진 상태에서 버튼 클릭(핫 리로드)을 너무 자주 반복하면, 에디터 내부에서 REINST_ClassName 같은 임시 클래스가 생성되거나 블루프린트 노드 연결이 끊기는 현상이 발생할 수 있습니다.



엑터

언리얼 엔진에서 게임에 배치될 수 있는 모든 객체를 통틀어서 액터라고 합니다.

액터의 이름을 입력하고 클래스 생성을 누릅니다 이때 액터 이름을 공백이나 한글로 하지 않는 걸 권장합니다.



UE_LOG(카테고리, 심각도, 출력 내용)

● 카테고리
로그가 어디서 발생했는지 분류하는 ‘이름표’입니다.

● 심각도 (Verbosity) 메시지의 중요도입니다. 설정에 따라 로그의 색상이 달라지고 에디터의 반응도 달라집니다.

심각도 (Verbosity)색상 (출력 로그)특징 및 용도
Log흰색 / 회색일반적인 정보 기록. 가장 많이 쓰임.
Display파란색콘솔 창에도 표시하고 싶은 강조 정보.
Warning노란색잠재적 문제 경고. 게임은 계속되지만 확인 필요.
Error빨간색명확한 오류 발생. 로직이 작동하지 않을 때 사용.
Fatal진한 빨간색치명적 오류. 로그 기록 즉시 에디터/게임 종료.

● 출력 내용 Output을 통해 출력할 내용을 입력하는 곳 입니다.

1
2
3
4
5
6
7
8
// 1. 단순 메시지 출력
UE_LOG(LogTemp, Log, TEXT("Hello Unreal World!"));

// 2. 변수와 함께 출력 (%s: 문자열, %d: 정수, %f: 실수)
FString PlayerName = TEXT("Wothingthing");
int32 Level = 10;
UE_LOG(LogTemp, Warning, TEXT("Player %s's Level is %d"), *PlayerName, Level);
//C 방식의 printf 스타일, FString 객체 자체가 아닌, 그 내부의 문자 배열 주소값(TCHAR*)을 원하기 때문에 포인터 연산자(*)를 사용
This post is licensed under CC BY 4.0 by the author.