Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 포인터, 스마트 포인터, 공유 포인터 완벽 가이드

포인터(Pointer)란?

포인터는 변수의 메모리 주소를 저장하는 변수입니다. C++에서 포인터를 활용하면 메모리에 직접 접근할 수 있어 효율적인 프로그래밍이 가능합니다.

선언 문법

Type *pointer;

초기화

Type *pointer;
pointer = &변수명;

포인터의 주요 특징

  • 변수의 메모리 주소를 저장합니다.
  • null 값을 할당할 수 있습니다.
  • 참조에 의한 전달(pass by reference)로 참조될 수 있습니다.
  • 포인터 자체도 스택(stack)에 고유한 메모리 주소와 크기를 가집니다.

포인터 예제

#include <iostream>
using namespace std;
int main() {
   // 일반 정수 변수
   int a = 7;
   // 변수 a의 주소를 저장하는 포인터 변수
   int *p = &a;
   // 포인터가 가리키는 값(변수 a의 값) 출력
   cout<<"Value of Variable : "<<*p<<endl;
   // 변수 a의 주소 출력
   cout<<"Address of Variable : "<<p<<endl;
   // 포인터를 통해 값 재할당
   *p = 6;
   cout<<"Value of the variable is now: "<<*p<<endl;
   return 0;
}

실행 결과

Value of Variable : 7
Address of Variable : 0x6ffe34
Value of the variable is now: 6

C++ 스마트 포인터(Smart Pointer)

스마트 포인터는 일반 포인터를 추상화하여 파일 처리, 네트워크 소켓 등과 같은 리소스에 대한 메모리 관리가 가능하도록 만든 추상 데이터 타입입니다. 이를 통해 자동 소멸(automatic destruction), 참조 카운팅(reference counting) 같은 기능을 구현할 수 있어 메모리 누수를 방지하는 데 큰 도움이 됩니다.

C++에서 스마트 포인터는 템플릿 클래스로 구현할 수 있으며, *(역참조) 연산자와 ->(화살표) 연산자를 오버로딩하여 일반 포인터처럼 동작하게 만듭니다. C++ 표준 라이브러리에서 제공하는 대표적인 스마트 포인터에는 auto_ptr, shared_ptr, unique_ptr, weak_ptr가 있습니다.

스마트 포인터 예제

#include<iostream>
using namespace std;
// 범용 스마트 포인터 클래스
template <class T>
class Smartpointer {
   T *p; // 실제 포인터
   public:
      // 생성자
      Smartpointer(T *ptr = NULL) {
         p = ptr;
      }
   // 소멸자 - 객체가 범위를 벗어나면 자동으로 메모리 해제
   ~Smartpointer() {
      delete(p);
   }
   // 역참조 연산자(*) 오버로딩
   T & operator * () {
      return *p;
   }
   // 화살표 연산자(->) 오버로딩
   // T의 멤버를 포인터처럼 접근할 수 있게 함
   T * operator -> () {
      return p;
   }
};
int main() {
   Smartpointer<int> p(new int());
   *p = 26;
   cout << "Value is: "<<*p;
   return 0;
}

실행 결과

Value is: 26

C++ 공유 포인터(shared_ptr)

shared_ptr은 C++ 라이브러리에서 제공하는 스마트 포인터의 한 형태입니다. 원시 포인터(raw pointer)를 감싸는 컨테이너 역할을 하며, 참조 카운팅(reference counting) 방식으로 소유권을 관리합니다. 참조 카운팅이란 객체, 메모리 블록, 디스크 공간 등의 리소스를 참조하는 포인터나 핸들의 개수를 저장하는 기법을 말합니다.

shared_ptr의 모든 복사본이 소멸되어 참조 카운트가 0이 될 때, 해당 원시 포인터가 가리키던 객체는 비로소 자동으로 파괴됩니다. 이 덕분에 여러 곳에서同一个 객체를 안전하게 공유하며 사용할 수 있습니다.

shared_ptr 예제

#include<iostream>
#include<memory>
using namespace std;
int main() {
   shared_ptr<int> ptr(new int(7));
   shared_ptr<int> ptr1(new int(6));
   cout << ptr << endl;
   cout << ptr1 << endl;
   // 동일한 관리 대상 객체를 참조하는
   // shared_ptr 객체의 개수를 반환
   cout << ptr.use_count() << endl;
   cout << ptr1.use_count() << endl;
   // ptr이 객체에 대한 소유권을 반납하고
   // 포인터는 NULL이 됨
   ptr.reset();
   cout << ptr.get() << endl;
   cout << ptr1.use_count() << endl;
   cout << ptr1.get() << endl;
   return 0;
}

실행 결과

0xe80900
0xe80940
1
1
0
1
0xe80940