728x90

황기태 저자의 명품 C++ Programming 개정판을 읽고 학습한 내용을 정리한 포스트입니다!

https://search.shopping.naver.com/book/catalog/32436115747

 

C++ Programming : 네이버 도서

네이버 도서 상세정보를 제공합니다.

search.shopping.naver.com

 

일반적으로 개발자는 프로그램 작성 단계에서 필요한 메모리를 확보하기 위해 변수, 객체, 배열을 정적으로 선언한다.

하지만, 사용자의 마음에 따라 달라지는 문서 편집기 등은 필요한 메모리를 프로그램 작성 단계에서 모두 선언하는 것은 불가능하다. 따라서, 이런 유형의 응용PR을 위해, 실행 중에 필요한 만큼 메모리를 할당받고 필요 없을 때 반환하는 '동적 메모리 할당/반환 메커니즘'이 필요

  • C언어에서는 동적 메모리 할당 및 반환을 위해 malloc() / free() 등의 표준 C함수를 이용
  • C++에서는 new와 delete 연산자를 이용한다.
  • new는 힙(heap)이라는 공간으로부터 메모리를 할당받는다.

 

new와 delete
데이터 타입 *포인터변수 = new 데이터타입;
delete 포인터변수;

 

  • new 연산자는 '데이터 타입'의 크기만큼 힙으로부터 메모리를 할당받고 주소를 리턴한다.
  • 그 결과 '포인터변수'는 할당받은 메모리의 주소를 가진다.
  • delete 연산자는 '포인터변수''가 가리키는 메모리를 힙으로 반환한다.
  • '데이터 타입'은 int, char, double 등 기본 타입뿐 아니라 구조체(struct), 클래스(class)도 포함한다.
int* pInt = new int; // int 타입의 정수 공간 할당
char* pChar = new char; // char 타입의 문자 공간 할당
Circle* pCircle = new Circle(); // Circle 클래스 타입의 객체 할당

delete pInt; // 할당받은 정수 공간 반환
delete pChar; // 할당받은 문자 공간 반환
delete pCircle; // 할당받은 객체 공간 반환
  • 동적 메모리를 할당받고 반환하는 간단한 코드
  • 힙 메모리가 부족하면 new는 NULL을 리턴하므로 검사하는 것이 좋다.
  • 아래는 INT 타입의 정수 공간 한 개를 할당 받고 사용한 후 반환하는 코드
int* p = new int; // 힙으로부터 int 타입의 정수 공간 할당
if (!p) { // if(p==NULL)과 동일. p가 NULL이면
	return; // 메모리 할당받기 실패
}
*p = 5; // 할당받은 정수 공간에 5기록
int n = *p; // 할당받은 정수 공간에서 값 읽기. n=5
delete p; // 할당받은 정수 공간 반환
  • 이 때, delete 후 포인터 p는 살아있지만, p가 가리키는 곳에 접근하면 안된다.
초기화
  • new를 이용하여 메모미를 할당 받을 때, '초깃값'을 지정하여 초기화할 수 있다.
// 데이터타입 *포인터변수 = new 데이터타입(초깃값);
int *pInt = new int(20); // 20으로 초기화된 int 공간 할당
char *pChar = new char('a'); // 'a'로 초기화된 char 공간 할당

 

  • delete 사용 시 주의사항
    • delete로 메모리를 반환할 때 적잘하지 못한 포인터를 사용하면, 실행 오류가 발생
int n;
int *p = &n;
delete p; // 실행 오류. p가 가리키는 메모리는 동적 할당받은 것이 아님

 


배열의 동적 할당 및 반환

배열의 동적 할당/반환의 기본 형식
// 데이터타입 *포인터변수 = new 데이터타입 [배열의크기]; // 배열의 동적할당
delete [] 포인터변수; // 배열 메모리 반환
  • new 연산자는 '배열의 크기'만한 배열을 할당받아 주소를 리턴
  • delete는 '포인터변수'가 가리키는 배열 메모리를 반환

 

초기화시 주의 사항
  • new로 배열을 동적 할당받을 때 다음과 같이 생성자를 통해 직접 '초깃값'을 지정할 수 없다.
int *pArray = new int [10][20]; // 구문 오류. 배열의 초기화는 불가
int *pArray = new int(20)[10]; // 구문 오류

// 아래와 같이 초깃값 지정
int *pArray = new int [] {1, 2,3, 4} // 1, 2,3, 4로 초기화된 정수 배열 생성

 

배열을 delete할 때 주의 사항
int *p = new int [10];
delete p; // 비정상 반환. deltete [] p;로 하여야 함
int *q = new int;
delete [] q; // 비정상 반환. delete q;로 하여야함

 


new를 이용한 객체의 동적 생성과 생성자

클래스이름 *포인터변수 = new 클래스이름; // 기본 생성자 호출
클래스이름 *포인터변수 = new 클래스이름(생성자매개변수리스트); // 매개변수 있는 생성자 호출
  • new는 클래스 크기의 메모리를 할당받아 객체를 생성하며, 이 때 생성자를 호출한다.

delete를 이용한 객체 반환과 소멸자

delete 포인터변수;
Circle *p = new Circle; // 생성자 Circle() 호출. p = new Circle();와 같음
Circle *q = new Circle(30); // 생성자 Circle(30) 호출

delete p;
delete q; // Circle 객체 반환
  • delete가 실행되면 객체를 반환하지 직전에 객체의 소멸자가 실행된다.

객체 배열의 동적 생성 및 반환

클래스이름 *포인터변수 = new 클래스이름 [배열 크기];
Circle *pArray = new Circle[3]; // 3개의 Circle 객체 배열의 동적 생성
Circle *pArray = new Circle[3](30); // 구문 오류, new를 이용하여 동적 배열 생성 시, 다음과 같이 매개 변수 있는 생성자 직접 호출 불가

// 대신 아래와 같이 각 원소 객체로 초기화 가능
Circle *pArray = new Circle[3] { Circle(1), Circle(2), Circle(3) };

 

객체 배열의 사용
  • 동적으로 생성된 객체 배열은 보통 객체 배열처럼 사용
Circle *pArray = new Circle[3]; // 객체 배열의 동적 생성

pArray[0].setRadius(10); // 배열의 첫 번째 객체의 setRadius() 멤버 함수 호출

//pArray가 포인터이므로 앞의 코드를 다음과 같이 작성 간으
pArray->setRadius(10);
(pArray + 1)->setRadius(20);

 

배열의 반환과 소멸자
delete [] 포인터변수; // 포인터변수가 가리키는 배열을 반환한다.
  • 또한, delete 배열은 생성의 반대 순서로 이루어진다.

Tip!! 동적으로 할당받은 메모리는 반드시 반환해야 하는가/

  • 힙(heap)은 프로그램이 실행 중 new를 이용하여 동적으로 할당받아 사용할 수 있는 메모리
  • 대부분의 OS에서는 PR마다 힙이 따로 주어지기 때문에, 서로 영향을 주지 않는다.
  • 다만, 필요없게 된 메모리를 반환하지 않거나 코딩 실수로 메모리 누수가 발생하면, 힙에 메모리가 부족하여 할당 받을 수 없게 되니 주의!!
  • 다행히 프로그램 종료 시, 힙 전체가 운영체제에 의해 반환 됨
메모리 누수(memory leak)
  • 동적으로 할당받은 메모리의 주소를 잃어버려 힙에 반환할 수 없게 되면 메모리 누수가 발생한다.
  • 메모리 누수가 계속 발생하여 힙의 크기가 줄어들게 되면, 실행 중 메모리를 할당받을 수 없는 심각한 상황이 발생
char n = 'a';
char *p = new char[1024];
p = &n;
  • 여기서 p가 n을 가리키면 할당받은 1024 바이트의 메모리 누수가 발생한다.
728x90

'Programming Language > C++' 카테고리의 다른 글

[C++] string 클래스를 이용한 문자열 사용  (1) 2023.12.01
[C++] this 포인터  (1) 2023.12.01
[C++] 객체 포인터와 객체 배열  (0) 2023.11.30
[C++] 포인터  (1) 2023.11.30
[C++] 구조체  (0) 2023.11.29