7.4 흔히 발생하는 메모리 관련 문제
메모리를 동적으로 관리하거나 로우레벨 연산을 수행하다보면 에러가 발생하기 쉬움
7.4.1 데이터 버퍼 과소 할당과 경계를 벗어난 메모리 접근
C스타일 스트링에서 '\0' 널문자의 공간을 생각못하고 공간을 할당하거나
스트링의 최대 크기를 정해놓아 초과해버릴때
- 경계를 벗어난 메모리 지점에 접근하여 동작을 예측할 수 없음
버퍼 오버플로 에러
7.4.2 메모리 누수
작성한 프로그램이 의도한 대로 결과를 내다가 실행 횟수가 늘어날수록 메모리 공간을 잡아먹는다
할당했던 메모리를 제때 해제하지 않을 때 발생. 댕글링 포인터 주의
스마트 포인터 쓰자
7.4.3 중복 삭제와 잘못된 포인터
포인터에 할당된 메모리를 delete로 해제하면 그 메모리를 프로그램의 다른 부분에서 사용할 수 있게 됨
하지만 해제 했다고 저장되어있던 데이터가 즉시 삭제되는것은 아니기 때문에 쓸 수는 있음<- 댕글링 포인터
중복 삭제와 메모리 재사용을 방지하려면 메모리를 해제한 후 항상 포인터값을 nullptr로 초기화 한다
7.5 스마트 포인터
메모리 누수를 방지하기 위해 적극 활용
스코프를 벗어나거나 리셋되면 할당된 리소스가 자동해제(unique_ptr 단독 소유권)
한 리소스를 여러 스마트 포인터가 가리키는 공동 소유권을 제공하는 고급기능도 있다
스코프를 벗어나거나 리셋될 때 리소스를 마지막으로 가리키는 스마트 포인터만 그 리소스를 해제할 수 있다(shared_ptr)
7.5.1 unique_ptr
단독 소유권을 제공. unique_ptr이 제거되거나 리셋되면 이 포인터가 가리키던 리소스가 자동으로 해제됨
메모리나 리소스를 반드시 해제시킬 수 있다는 장점. return문이나 익셉션이 발생했을때도 자동 해제
delete를 꼬박꼬박 해주기도 힘들뿐더러 꼬박꼬박 적어줬다 해도 프로그램이 강제로 종료되면 해제가 안될 수 있으므로 스마트 포인터를 꼭 활용하자
make_unique() 함수로 유니크 포인터를 초기화 한다. 값 초기화를 사용하므로 기본타입은 0으로 초기화 되고 객체는 디폴트로 초기화 된다.
unique_ptr도 일반적인 포인터와 똑같이 *나 ->로 역참조한다
reset()을 이용하면 unique_ptr의 내부 포인터를 해제하고 필요하다면 이를 다른 포인터로 변경 가능
release()를 이용하면 unique_ptr과 내부 포인터의 관계를 끊을 수 있다
unique_ptr은 단독 소유권을 표현하기 때문에 복사할 수 없음
unique_ptr은 C 스타일의 동적 할당 배열을 저장하는 데 적합하다
C++문법을 사용하면서 까지 C 배열을 사용할 필요가 없으므로 array나 vector 쓰자
7.5.2 shared_ptr
복제 가능한 공유 소유권을 제공한다.
동일한 리소스를 가리키는 shared_ptr인스턴스가 여러 개일 때 해당 리소스를 해제할 시점을 어떻게 알아낼까?
-> 레버런스 카운팅(참조 횟수 계산) 이란 기법을 통해 해결
unique_ptr과 비슷하게 make_shared()로 생성. CTAD도 사용 불가. 반드시 템플릿 타입 명시
레퍼런스 카운팅
클래스의 인스턴스 수나 현재 사용중인 특정 객체를 추적하는 메커니즘
실제 포인터를 참조하는 스마트 포인터의 개수를 추적한다.
스마트 포인터가 복제될 때마다 동일한 리소스를 가리키는 인스턴스가 새로 생성되면서 레퍼런스 카운터가 하나 증가한다. 이런 스마트 포인터 인스턴스가 스코프를 벗어나거나 리셋되며 레퍼런스 카운터가 하나 감소-> 카운터가 0이되면 마지막 남은 스마트 포인터가 그 리소스를 해제
new 를 이용한 일반 포인터로 할당한 메모리를 스마트 포인터로 참조할 경우 동작을 보장할 수 없거나 뻗으니 주의
그냥 스마트 포인터 사용하라고!!
shared_ptr도 캐스팅 가능
앨리어싱도 가능. 소유한 포인터를 다른 shared_ptr과 공유하면서 저장된 포인터를 가리킬 수 있다.
두 마트포인터가 각각 객체와 그 객체의 멤버를 가리킨다
이럴경우 두개 다 삭제될때만 객체가 삭제된다
weak_ptr
shared_ptr이 관리하는 리소스에 대한 레퍼런스를 가질 수 있다.
리소스를 직접 소유하지 않기 때문에 shared_ptr이 해당 리소스를 해제하는 데 아무런 영향을 미치지 않는다.
shared_ptr이 그 리소스를 해제했는지 여부를 확인하는 데 사용할 수 있다.
weak_ptr의 생성자는 shared_ptr이나 다른 weak을 인수로 받음
그 포인터에 접근하려면 shared로 변환해야됨
7.5.4 함수에 전달하기
매개변수로 포인터를 받는 함수는 소유권을 전달하거나 공유할 경우에만 스마트 포인터를 사용
7.5.5 함수에서 리턴하기
리턴값 최적화(RVO) 이름있는 리턴값 최적화 (NRVO), 이동의미론 덕분에 쉽고 효율적으로 처리
7.5.6 enable_shared_from_this
이걸 상속해서 클래스를 만들면 객체에 대해 호출한 메서드가 자신에게 shared_ptr이나 weak_ptr을 안전하게 리턴할 수 있다.
~380p
'전문가를 위한 C++' 카테고리의 다른 글
2025/03/06 ch.09 클래스와 객체 완전 정복 (0) | 2025.03.06 |
---|---|
2025/03/05 ch.08 클래스와 객체 이해 (0) | 2025.03.05 |
2025/03/03 ch.07 전문가답게 C++ 코딩하기 (0) | 2025.03.03 |
2025/03/02 ch.06 재사용을 고려한 설계 (0) | 2025.03.02 |
2025/02/28 ch.05 객체지향 설계 (0) | 2025.02.28 |