언어/C++

RAII, C++ 포인터

에린_1 2025. 7. 15. 20:24
728x90

학습목표

  1. C++의 전통적인 포인터(new/ delete)가 왜 위험한지 이해한다.
  2. RAII(Resource Acquisition Is Initialization)라는 핵심 원칙을 설명할 수 있다.
  3. 소유권을 독점하는 std::unique_ptr의 특징과 사용법을 익힌다.
  4. 소유권을 공유하는 std::shared_ptr의 특징과 사용법을 익힌다.

핵심 키워드

  • 메모리 누수(memory leak)
  • RAII(Resource Acquisition Is Initialization)
  • 소유권(Ownership)
  • std::unique_ptr
  • std::shared_ptr
  • std::make_unique/std::make_shared

1.문제

c++에서 동적할당한 메모리는 반드시 해제해줘야한다. 해제를 하지 못하면 그 메모리는 누수가 일어난다.

2. 해결

RAII (Resource Acquisition Is Initialization)패턴

  • 자원을 획득하는 시점은, 그 자원을 관리할 ‘객채’의 ‘생성 시점’과 일치해야 한다.

메모리(자원)을 new로 직접 다루지 말고, 메모리를 관리하는 객체(스마트 포인터)를 만들어서 그 객체에게 관리를 맡기자는 것.

객체는 자기가 사라질 때소멸자가 자동으로 호출되면서 delete를 처리하도록 일을 수행한다.

3. 사용법

  • 소유권 독점: std::unique_ptr
    • unique_ptr은 이름 그대로 ‘유일한’ 소유권을 가진다. 복사는 불가능하고, 소유권을 다른 unique_ptr에게 이동시키는 것만 가능하다.
    • 가볍고 빨라서 기본적으로 사용하는 스마트 포인터이다.
    #include <memory> // 스마트 포인터를 사용하려면 꼭 포함해야 한다.
    
    void processPlayer_safe()
    {
    	//이렇게 만들면 Player 객체의 소유권은 p가 가지게 된다.
    	//std::make_unique를 쓰는 것이 가장 안전하고 좋은 방법이다.
    	std::unique_ptr<Player> p = std::make_unique<Player>();
    	
    	p->doSomething();
    }
    // 함수가 끝나면 p가 사라지면서, 자기가 가리키던 Player 메모리를 자동으로 해제한다.
    
  • 소유권 공유:std::shared_ptr
    • 공유라는 이름처럼, 하나의 메모리를 여러 shared_ptr이 함께 가리키며 공동으로 소유할 수 있다.
    • 내부적으로 참조 카운트(Reference Count)라는 걸 가지고 있어서, 자신을 가리키는 shared_ptr이 몇 개인지 세고 있다.
      • 새로운 shared_ptr가 같은 메모리를 가리키면 참조 카운트가 1증가한다.
      • hared_ptr가 사라지면(스코프를 벗어나거나 다른 값을 할당받으면) 참조 카운트가 1 감소한다.
      • 참조 카운트가 0이 되는 바로 그 순간, 마지막 남은 shared_ptr가 메모리를 delete 해준다.
    • MMORPG에서 한 명의 플레이어가 파티 목록에도 있고, 공격대 목록에도 있을 때처럼 여러 곳에서 동일한 객체를 참조해야 할 때 유용하다.
    #include <memory>
    #include <vector>
    
    //플레이어를 가리키는 포인터를 담을 리스트
    std::vector<std::shared_ptr<Player>> party_list;
    std::vector<std::shared_ptr<Player>> raid_list;
    
    void managePlayer()
    {
    	//플레이어를 만들고 p1이 소유(참조 카운트1)
    	std::shared_ptr<Player> p1 = std::make_shared<Player>();
    	
    	//파티리스트에 p1을 복사. 이제 p1과 list의 원소가 함께 소유(참조 카운트2)
    	party_list.push_back(p1);
    	//레이드리스트에도 p1을 복사(참조 카운트3)
    	raid_list.push_back(p1);
    }
    // 함수가 끝나면 p1은 사라지지만, 
    // 아직 list들이 객체를 가리키고 있으므로 참조 카운트는 2가되고 메모리는 해제되지 않는다.
    

 

728x90

'언어 > C++' 카테고리의 다른 글

클래스(Class)  (0) 2024.11.26
구조체(Struct)  (0) 2024.11.24
참조자(Reference)  (0) 2024.11.24
인라인(inline) 함수  (0) 2024.11.24
Call by Value/Call by Reference  (0) 2024.11.24