2026-03-06(금)

조범근·2026년 3월 6일

TIL

목록 보기
11/25

헷갈리는게 너무 많아졌다. 이론을 머릿속에 집어넣는 것 보단 회독을 하는게 좋을 듯.

C++


Q1. 순수가상함수가 뭔가요? 왜 쓰는건가요?

A1. virtual (자료형)(함수명)() 기본구조


Q. 그래서 왜 씀?

언리얼의 Interact(상호작용) 기능을 만든다고 치자. 그럼 문, 보물상자, NPC 등 상호작용 대상이 수천개다.

여기서 Target이 어떤 오브젝트인지 알 필요 없이 상속 받았으면 실행하라고 시킬 수 있음.



Q2. vector가 머임

A2. vector<기본클래스*>_ 변수;

#include <vector>
    vector<Phone*> Phones;

vector는 길이가 마음대로 늘어났다 줄어들었다 하는 편한 동적배열
그러므로 뒤에 해제 delete도 해줘야함.

Q. vector 동적배열 반복문을 쓸때 int i = 0;이 아니라 size_t 인 이유가 뭔가요

for(size_t i = 0; i < Phones.size(); i++){
        Phones[i].Display();
}

vector::size() 함수 자체가 반환하는 타입이 size_t(size_type)으로 정해져 있기 때문
(size_t는 절대 음수가 될 수 없는 자료형 unsigned int와 크기가 같음)



Q3. push_back은 뭐하는건가요?

#include <vector>
    vector<Phone*> Phones;
    Phones.push_back(new Samsung());

A3. push_back은 맨 뒤에 새로운 칸을 만들어서 데이터를 넣는 함수이다.
Phones.push_back(new Samsung());은 Phones[0]에 Samsung을 동적할당 해준거임.
이건 선언한 순서대로 Phones[1], Phones[2] 가 됨



Q4. ~(클래스명)에서 ~이게 소멸자라는데 뭐임??

A4. 소멸자는 클래스가 할당이 해제 될때 실행됨. 생성자의 반대라고 알면 될 듯

virtual ~Phone() {delete Phone;} 

Q. 언제 쓰는건가요??

A.
1. 클래스 내부 동적할당 해제할때
2. 아까 main에서 동적할당 했을때 delete Phones[i] 반복문을 돌리는데 이렇게 되면 기본 클래스에 있는 메모리만 해제하게 됨. virtual ~Phone(){}는 delete가 파생 메모리들도 찾아갈 수 있게 인식키 같은게 되는거임.

Delete Phones[0]을 실행하면 다음과 같이 행동한다.

  1. Phone[0] 주소로 간다.

  2. 포인터 타입이 Phone*인걸 확인

  3. Phone의 메모리만 해제

  4. 결과 : Samsung 객체 중 Phone과 겹치는 기본 클래스만 지워지고 파생 클래스의 데이터는 메모리에 남아 메모리 누수 됨.

결론

  • Phones[0]은 Samsung을 가리키는가? -> YES

  • 컴퓨터는 지울 때 Samsung인 걸 자동으로 아는가? -> NO. (virtual이 있어야함)

  • 왜 virtual을 쓰는가? -> 기본 클래스에 상속된 파생 클래스의 할당된 메모리를 해제 하기 위해



Q5. unique_ptr이 뭐에요?

A5.

std::unique_ptr<Phone> ptr;  // 기본형

포인터의 주소 복사가 안되는 포인터 옮기는건 move 사용해서 가능. 즉 같은 주소를 가진 포인터가 두개 이상 존재 할 수 없음

std::unique_ptr<Phone> ptr = std::make_unique<Phone>;
std::unique_ptr<Phone> ptr2 = ptr; // 복사가 안됨

여기서 좀 헷갈렸는데 어려울것 없다. 그냥 원래 보던 함수랑 똑같다고 생각하면 됨.

unique_ptr<Phone> ptr = make_unique<Phone>;

  • unique_ptr<Phone> : 포인터 주소로 갔을때 값의 크기가 클래스 Phone만큼(포인터 변수 ptr 주소값의 크기 X) 입니다 안심하고 들어오세요~ 라는 뜻

  • ptr : 포인터 변수

  • make_unique<Phone> : 클래스 Phone 크기만큼 동적할당 하겠습니다.

즉, (자동반환이 되고 주소값을 가리키는 포인터는 하나인) Phone 크기만큼 동적할당을 할게요 !
-> ptr 포인터 변수에 동적할당 할게요 !
-> 포인터 변수 주소의 값에는 클래스 Phone만큼의 크기가 있으니 안심하고 들어오세요 !

처음에 너무 낯설어서 헷갈렸지만 거꾸로 읽으면 그냥 포인터 선언 한거임..



Q6. weak포인터 if(auto a_shared = ptr.lock()) <- 이놈 때문에 미칠 것 같아요. 이거 뭐죠

A. weak_ptr레퍼런스 카운트를 증가시키지 않는 약한 참조방식으로 동작하는 스마트 포인터 입니다.

라고 하지만 글로만 보면 이해가 안된다. 그렇다고 또 예문을 보면 미쳐 돌아버릴 것 같다.

class B {
public:
    std::weak_ptr<A> a_ptr;

    void useA() {
        if (auto a_shared = a_ptr.lock()) { // 유효한지 확인
            a_shared->say_hello();
        } else {
            std::cout << "A is no longer available.\n";
        }
    }
};

일단은 모르는게 너무 많으니까 뭔지 보고 가자

  1. auto a_shared에서 auto 자료형은 뭐죠**

    A. auto는 컴파일러가 타입을 추론 한다.
    즉, 초기값의 형식에 맟춰 선언하는 인스턴스(변수)의 형식이 '자동'으로 결정된다.

  2. a_ptr.lock()에서 .lock() 또 뭐에요??

    A. a_ptr.lock()weak_ptr보고 있는 객체가 진짜로 살아 있는지 확인하고 if 안 에서는 사용할 수 있게 잠금을 해놓겠다이다.

이 두개를 이해해야지만 weak에 대한 이해를 할 수 있음

지금 위에서 한 week_ptr은 약한참조(보기만 할 수 있음) 주소 값이 살아 있으니까 autostd::shared_ptr<A>승격 된다. << 이때 레퍼런스 횟수가 1 올라감, 죽었으면 nullptr 반환
즉, std::shared_ptr< A > a_shared가 됐다

weak_ptr을 쓰는 경우

A도 B에 포인터를 쓰고싶고, B도 A에 쓰고싶은데 둘이 shared_ptr을 쓰면 무한반복 되니까

B에서는 weak_ptr을 써서 if(auto a_ptr = ptr.lock()){} 스코프 안에서만 A를 참조해서 쓴다!!




결론 어디에 뭘 써야할지 헷갈린다면?

vector, std::unique_ptr, push_back, weak_ptr 다 모르겠다!!

넣을때는 make_unique, 상자는 vector<unique_ptr<T>>, 모르면 외워!!

0개의 댓글