메모리 할당과 해제
변수가 사용할 공간은 new 키워드로 생성한다.
다 사용한 후 프로그램의 다른 영역에서 재사용 하도록 이 공간을 해제하려면 delete 키워드를 사용한다.
1. new와 delete 사용법
변수에 필요한 메모리 블록을 할당하려면 new에 그 변수의 타입을 지정해서 호출한다.
그러면 할당된 메모리에 대한 포인터가 리턴된다.
메모리 누수
new의 리턴값을 무시하거나 그 포인터를 담았던 변수가 스코프를 벗어나면 할당했던 메모리에 접근할 수 없다.
이를 메모리 누수(메모리 릭)라 부른다.
다음 코든는 int를 다음 골간 만큼 메모리 누수가 발생하는 예를 보여준다.
void leaky()
{
new int; // 버그, 메모리 누사가 발생한다.
cout << "방금 int 하나를 잃어버렸다." << endl;
}
다음은 이 코드를 실행한 후의 메모리 상태를 보여준다.
스택에서 직접적이든 간접적이든 더 이상 접근 할 수 없는 데이터 블록이 힙에 발생하면 메모리 누수가 발생한다.
한 객체에 할당했던 메모리를 다른 용도로 사용할 수 있도록 해제해야 한다.
힙 메모리를 해제하려면 다음과 같이 delete 키워드에 해제할 메모리를 가리키는 포인터를 지정한다.
int* ptr = new int;
delete ptr;
ptr = nullptr;
new로 메모리를 할당할 때 스마트 포인터가 아닌 일반 포인터로 저장했다면 반드시 그 메모리를 해제하는 delete 문을 new와 짝을 이루도록 작성해야 한다. 메모리를 해제한 포인터는 nullptr로 다시 초기화 한다. 그래야 이미 해제된 메모리를 가리키는 포인터를 모르고 다시 사용하는 실수를 방지할 수 있다.
2. malloc(), free()
C에서 malloc()은 인수로 지정한 바이트 수만큼 메모리를 할당한다.
C++은 여전히 malloc()을 지원하지만 malloc() 대신 new를 사용하는 것이 좋다.
new는 단순히 메모리를 할당하는 데 그치지 않고 객체까지 만들기 때문이다.
다음은 Foo라는 클래스의 객체를 생성하는 코드이다.
Foo* myFoo = (Foo*)malloc(sizeof(Foo));
Foo* myOtherFoo = new Foo();
이 문장을 실행하면 Foo 객체를 저장하는 데 충분한 크기의 힙 영역을 할당해서
이를 가리키는 포인터를 myFoo와 myOtherFoo에 저장한다.
Foo의 데이터 멤버와 메서드는 이 두 포인터로 접근할 수 있는데, myFoo가 가리키는 Foo 객체는 생성되지 않았다.
malloc() 함수는 메모리에서 일정한 영역만 따로 빼놓을 뿐 객체에 대해서는 아무런 관심도 없다.
반면 new를 호출한 문장은 적절한 크기의 메모리 공간이 할당될 뿐만 아니라 Foo의 생성자를 호출해서 객체를 생성한다.
free() 함수와 delete의 관계도 이와 비슷하다.
free()는 객체의 소멸자를 호출하지 않는 반면 delete는 소멸자를 호출해서 객체를 정상적으로 제거한다.
free(myFoo);
delete myOtherFoo;
myOtherFoo = nullptr;
3. 메모리 할당에 실패한 경우(nothrow)
new는 항상 제대로 처리되지 않는다.
메모리가 부족해서 상황이 좋지 않을때는 new가 실패한다.
기본적으로 new가 실패하면 프로그램이 종료된다.
new로 요청한 만큼의 메모리가 없어서 익셉션(예외)이 발생하면 프로그램이 종료된다.
익셉션이 발생하지 않는 버전의 new도 있다.
이 버전은 익셉션 대신 nullptr을 리턴한다.
int* ptr = new(nothrow) int;
익셉션을 던지는 버전과 마찬가지로 메모리가 부족해서 nullptr를 리턴하더라도 이 상황을 처리해줘야 한다.
이를 검사하는 코드를 작성하지 않아도 컴파일하는 데 문제는 없다.
그래서 익셉션을 던지는 버전보다 nothrow 버전을 사용할 때 버그가 발생할 가능성이 있다.
이러한 이유로 보통 nothrow 버전보다는 표준 버전의 new를 사용한다.
'💻프로그래밍 내용 정리 > C++17' 카테고리의 다른 글
[C++ 7.1.3-2] 다차원 배열 (0) | 2022.08.22 |
---|---|
[C++ 7.1.3-1] 배열, 객체 배열, 배열 삭제 (1) | 2022.08.22 |
[C++ 7.1.1] 동적 메모리 작동 과정 살펴보기 (0) | 2022.08.22 |
[C++ 2.1.4] std::string_view 클래스 (1) | 2022.08.20 |
[C++ 2.1.3-2] 하이레벨 숫자 변환(to_string, stoi), 로우레벨 숫자 변환(to_chars, from_chars) (0) | 2022.08.20 |