Post

2026-03-05 TIL (8일차)

2026-03-05 TIL (8일차)

C++ 강의 (2주차)

  1. 스마트 포인터
    원리: 스마트 원리의 핵심 원리는 new / delete를 사용하지 않는 자동 메모리 관리

    unique_ptr
    ● 힙 메모리에 대해 독점적 소유권을 가지는 스마트 포인터 (주소 하나에 포인터 하나)
    ● 소유권 이전은 가능하지만 동시에 가리키는거는 불가

    shared_ptr
    ● 하나의 자원(힙 메모리)을 여러 포인터가 공동 소유하며, 참조 횟수(Reference Count)가 0이 될 때 자동으로 메모리를 해제하는 포인터
    ● 참초 횟수: 소유하고 있는 포인터 갯수
    ● 문제점: 순환참조를 하게되면 해제가 불가능 하다. (힙 메모리에 내용을 파괴할 때 자신을 가리키고 있는 포인터가 아직 남아있으므로 계속 남아있게 된다.)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    class Cat
    {
    public:
        Cat(std::string name) : mName{ name }
        {
            std::cout << mName << " cat constructor" << std::endl;
        }
    	~Cat()
        {
            std::cout << mName << " cat destructor" << std::endl;
        }
        std::shared_ptr<Cat> mVar;
    private:
    	std::string mName;
    };
    
    int main()
    {
        std::shared_ptr<Cat> kitty = std::make_shared<Cat>("kitty");
        std::shared_ptr<Cat> nabi = std::make_shared<Cat>("nabi");
    
        kitty->mVar = nabi;
        nabi->mVar = kitty;
    
        std::cout << "kitty count : " << kitty.use_count() << std::endl;
        std::cout << "nabi count : " << nabi.use_count() << std::endl;
    }
    

    weak_ptr (shared_ptr과 연관이 있음)
    ● 객체를 가리키기는 하지만, 소유권(참조 횟수)을 주장하지 않는 지켜보기 전용 포인터
    ● shared_ptr을 가리키고 있는 주소값을 똑같이 weak_ptr이 가리키게 해도 참조 횟수가 증가하지 않는다.
    ● shared_ptr의 문제점인 순환참조가 안일어나게 할 수 있다.
    ● weak_ptr에서 lock()은 객체가 살아있는지 확인하고, 살아있다면 내가 안전하게 사용할 수 있도록 ‘임시 소유권’을 빌려오는 기능이고 사용이 끝나면 빌려온 권한은 자동으로 사라지고, 객체는 다시 언제든 파괴될 수 있는 상태로 돌아간다.

  2. 언리얼 엔진 메모리관리

    가비지 컬렉션
    더 이상 아무도 쓰지 않는 메모리(객체)를 엔진이 알아서 청소해 주는 시스템
    루트셋(Root Set)에 제외한 모든 객체는 가비지 컬렉션에 들어감

    루트셋: 무조건 삭제시키지말고 놔둬야한다는 최상위 객체 목록
    ex) Game Instance, World, Player Controller, Engine Subsystems 등

    언리얼 엔진 메모리 관리 객체 분류

    구분가비지컬렉션 수거 여부판단 기준예시
    생존 객체제외루트셋 그 자체이거나, 루트셋으로부터 참조(UPROPERTY)이 연결되어 있음루트셋, 참조된 객체
    가비지 객체대상루트셋으로부터 연결된 참조가 없는 상태Destroy된 액터, 참조를 잃은 UObject, 함수 안의 지역 변수, 생성만 하고 어디에도 등록 안 한 UI

    마크 앤 스윕 알고리즘
    첫번째 단계: 루트셋에서 포함된 객체 식별
    두번째 단계: 루트셋 객체에서 직간접적으로 참조하는 객체를 판단하고 마크함
    세번째 단계: 마크 단계가 완료되면 마크되지 않은 객체들이 차지하고 있던 메모리를 회수

    가비지 컬렉션은 단순히 지운다,안 지운다를 넘어, 각 객체의 상태를 플래그(Flag)라는 꼬리표로 관리
    ● RF_RootSet: 개발자가 직접 수동으로 관리하겠다.수동으로 지우기 전까지 건드리지 마라는 플래그

    ● RF_BeginDestroyed(시스템이 내부적으로 관리하는 값)
    파괴 로직을 막 시작한 단계, BeginDestroyed() 가상 함수가 호출되었음을 의미
    이 상태의 객체는 아직 메모리에 데이터는 남아있지만, 더 이상 정상적인 기능을 수행할 수 없습니다.

    ● RF_FinishDestroyed(시스템이 내부적으로 관리하는 상태 값)
    모든 파괴 준비 작업이 끝난 단계, inishDestroyed() 가상 함수가 호출되었음을 의미
    객체가 차지하던 공간을 비우기 직전의 마지막 단계, 이 플래그가 찍히면 더 이상 엔진의 어떤 시스템도 이 객체에 접근해서는 안 됨.

    리플렉션 시스템
    엔진이 코드를 실시간으로 인식하고 에디터 노출·가비지 컬렉션·블루프린트와 연동할 수 있게 만드는 통역 시스템
    (기본 c++로 하면 언리얼 엔진에서 못받아들이고 사용을 못함)

C++ 공부

상속받은 클래스의 생성자 정의
● 자식 클래스의 생성자는 부모 클래스의 멤버까지 초기화(생성자 호출)해야 할 의무가 있다.
● 자식은 부모의 구성까지 생성이 되므로 자식 클래스 생성자는, 부모 클래스의 생성자를 호출해서 부모 클래스의 멤버를 초기화 하는 것이 좋다.

자식 클래스 생성 과정
● 자식 클래스의 객체생성 과정에서 부모 클래스의 생성자는 100% (대부분 먼저)호출된다.
● 자식 클래스의 생성자에서 부모 클래스의 생성자 호출을 명시하지 않으면, 기초 클래스의 void 생성자가 호출된다.

자식 클래스 객체의 소멸과정
● 자식 클래스의 객체가 소멸될 때에는, 자식 클래스의 소멸자가 실행되고 난 다음에 부모 클래스의 소멸자가 실행된다.
● 스택에 생성된 객체의 소멸순서는 생성순서와 반대이다.

상속 형태의 3가지

접근 제한자본인 클래스자식 클래스외부
public✅ 가능✅ 가능✅ 가능
protected✅ 가능✅ 가능❌ 불가
private✅ 가능❌ 불가❌ 불가

Is-A와 Has-A차이

구분IS-A (상속)HAS-A (구성)
관계클래스 간의 수직적 관계객체 간의 수평적/포함 관계
결합도강함 (부모가 바뀌면 자식도 바뀜)약함 (부품만 교체하면 됨)
유연성낮음 (설계 시점에 결정됨)높음 (실행 중에 바꿀 수 있음)
코드 재사용부모의 코드를 그대로 물려받음필요한 기능을 가진 객체를 가져다 씀
1
2
3
4
5
6
   class A
   {
   }
   class B : public A
   {
   }
1
2
3
4
5
6
7
   class A
   {
   }
   class B
   {
     A* aptr
   }
This post is licensed under CC BY 4.0 by the author.