Effective C++
Chapter 8 정리
new와 delete를 내 맘대로
들어가기에 앞서
- 가비지 컬렉터가 없는 C++, 불편하지만 이점도 있다
- 메모리를 수동으로 관리하고 싶다!면 C++!
- Operator new, delete 문제, 다중쓰레드에서의 메모리 관리 문제등등!
- 이번 챕터를 통해서 해결해보자
- STL 컨테이너와 관련된 메모리 관리도!
Item 49
new 처리자(new handler)의
동작 원리를 제대로 이해하자
Item 49 : new 처리자의 동작원리를 제대로 이해하자
- operator new를 통해 메모리를 획득하지 못한 경우(즉, 할당할 메모리가 없을 때)
- operator new는 예외를 던진다
- 메모리 할당이 제대로 되지 못한 경우,
예외를 던지기 전에 에러 처리 함수를 먼저 호출하게 되어있다
이 에러 처리 함수를 new 처리자(할당 에러 처리자)라 한다
- 표준에는 이 new 처리자를 사용자가 지정해 줄 수 있는 함수가 존재한다
- 바로 set_new_handler
Item 49 : new 처리자의 동작원리를 제대로 이해하자
- set_new_handler의 사용 방법
void outOfMem (){
std : : cerr << "Unable to sat isfy r equest for memoryn ";
std : : abort ( ) ;
}
-----------------------------------------------------------------------------------------------------
int main (){
std : : set_ new_ handler (outOfMem) ; // 사용자 정의 new handler 설정
int *pBigDataArray = new int [1 00000000L] ;
}
1억개의 정수가 할당되지 못하면? outOfMem이 호출된다. 그리고 std::abort에 의해
프로그램이 종료된다.
Item 49 : new 처리자의 동작원리를 제대로 이해하자
- new 처리자 함수의 지향점
1. 사용할 수 있는 메모리를 더 많이 확보하는 쪽
2. 다른 new 처리자를 부르는 쪽 -> 현재의 new 처리자로는 메모리를 할당할 수 없으므
로
3. new 처리자를 제거하는 쪽 -> 바로 예외를 던짐
4. 제거고 뭐고 그냥 예외를 던지는 쪽
5. 프로그램을 끝내는 쪽
- 위 5개 중 한 쪽을 택해 new 처리자를 구현해야 한다.
Item 49 : new 처리자의 동작원리를 제대로 이해하자
- 클래스 별로 다른 new 처리자를 만들고 싶다면? ( Widget의 예를 통해 알아 보자)
class Widget (
public :
static std: :new_handler set_new_handler(std: :new_handler p) throw();
static void * operator new(std: :size_t size) throw(std : : bad_ alloc) ;
private :
static std::new_handler currentHandler; // static이니 구현은 cpp에서 해준다
}
static을 사용하는 이유는 new를 실행하다 실패하면 new_handler를 부르기 때문에
Widget 생성되기 전에 존재해야 한다.
Item 49 : new 처리자의 동작원리를 제대로 이해하자
- 클래스 별로 다른 new 처리자를 만들고 싶다면? ( Widget의 예를 통해 알아 보자)
class Widget (
public :
static std: :new_handler set_new_handler(std: :new_handler p) throw();
static void * operator new(std: :size_t size) throw(std : : bad_ alloc) ;
private :
static std::new_handler currentHandler; // static이니 구현은 cpp에서 해준다
}
static을 사용하는 이유는 new를 실행하다 실패하면 new_handler를 부르기 때문에
Widget 생성되기 전에 존재해야 한다.
Item 49 : new 처리자의 동작원리를 제대로 이해하자
- Widget::set_new_handler 구현 부분
std : :new_handler Widget : : set_new_handler(std : :new_handler p) throw() {
std : :new_handler oldHandler = currentHandler ;
currentHandler = p ;
// 원래 표준 set_new_handler처럼 인자를 currentHandler로 설정하고
// old를 반환한다.
return oldHandler ;
}
Item 49 : new 처리자의 동작원리를 제대로 이해하자
Widget만의 operator new 구현하기 위해 new Handler 관리 클래스 선언
class NewHandlerHolder {
public :
explicit NewHandlerHolder(std : :new_handler nh) : handler(nh) {}
~NewHandlerHolder()
{ std: :set_new_handler(handler) ; } // 소멸자에서 하는 작업 뒤에서 설명
private :
std::new_handler handler;
NewHandlerHolder(const NewHandlerHolder&) ; // 복사 막기위해
NewHandlerHolder&
operator=(const NewHandlerHolder&);
}
Item 49 : new 처리자의 동작원리를 제대로 이해하자
Widget만의 operator new 구현
void * Widget : :operator new(std: : size_t size) throw(std : :bad_alloc) {
// set_new_handle의 반환 값은 기존의 new 처리자이다.
// 따라서 NewHandlerHolder::handler는 기존의 new 처리자를 갖는다
NewHandlerHolder h(std: : set_new_handler(currentHandler)) ;
// 표준 할당자로 할당함
return : :operator new(size);
}
// NewHandlerHolder의 소멸자에서 기존의 new 처리자로 되돌리는 것을 알 수 있다.
이후에는 템플릿으로 만드는 법이 나온다. 이는 다음에 자세히 살피고 이번 Item을 넘어가
자
Item 50
new, delete는 언제 바꿀까?
Item 50 : custom operator new, delete를 사용하는 경우
1. 잘못된 힙 사용을 탐지하기 위해
- operator new에서 할당된 메모리 주소의 목록을 유지
- operator delete에서 그 목록으로부터 하나씩 제거
- 한 번 new한 객체를 두 번 delete하는 경우가 없게!
- overrun(할당된 메모리 블록 끝을 넘어 기록하는 것)
- underrun(할당된 메모리 블록을 앞서 기록하는 것)
- over,under run 문제 방지
Item 50 : custom operator new, delete를 사용하는 경우
2. 효율 향상을 위해
- 컴파일러가 기본으로 제공하는 new, delete는 다양한 요구사항을 맞추기 위해 무난하
게 동작함
- 개발자가 자신에 맞는 동적 메모리 사용 방식을 정확히 안다면 `우수한 성능`의 new,
delete 만들기 가능
- 실행속도가 빠르고(최대 10의 n제곱배) 메모리도 적게 차지하는(50%만 사용) 버전 만
들기 가능
Item 50 : custom operator new, delete를 사용하는 경우
3. 동적 할당 메모리의 실제 사용에 관한 통계 정보를 수집하기 위해
- 할당되는 메모리 블록의 크기 값들에 대한 정보
- 메모리 할당 순서가 FIFO, LIFO 인지
- 각 실행단계에서의 메모리 블록 할당이 어떻게 이루어지고 있는지
- 등등의 정보를 모으기 위해
Item 50 : custom operator new, delete를 사용하는 경우
3. 동적 할당 메모리의 실제 사용에 관한 통계 정보를 수집하기 위해
- 할당되는 메모리 블록의 크기 값들에 대한 정보
- 메모리 할당 순서가 FIFO, LIFO 인지
- 각 실행단계에서의 메모리 블록 할당이 어떻게 이루어지고 있는지
- 등등의 정보를 모으기 위해
Item 50 : custom operator new, delete를 사용하는 경우
여기서 잠깐! operator new를 만들 때 주의할 점 : 바이트 정렬(alignment)
- 컴퓨터는 대부분의 경우 특정 종류의 메모리 주소를 시작 주소로 하여 저장될 것을 요
구한다
- 무슨 말이고? 만약 4의 배수를 기준으로 각 객체가 저장되어야 한다면 객체들의 시작
주소는 언제나 0, 4, 8 ,c로 끝난다.
- 컴퓨터에 따라서 8byte일 수도, 4byte일 수도, 조금 다른 수 일 수 도 있다.
- 어떤 아키텍처이냐에 따라 바이트 정렬이 안되면 프로그램이 실행되다가 하드웨어 예
외를 일으킬 수 있다
- x86은 어떤 바이트 단위에 맞추더라도 실행할 수 있지만 8바이트 단위로 정렬하면 런타
임 접근속도가 훨씬 빨라진다
Item 50 : custom operator new, delete를 사용하는 경우
4. 할당 및 해제 속력을 높이기 위해
- 기본 제공 new는 느린 경우도 많다
- 특정 크기를 할당할 일이 많으면 직접 만들어 속도에서 향상을 만들어 낼 수 있다
Item 50 : custom operator new, delete를 사용하는 경우
5. 임의의 관계를 맺고 있는 객체들을 한 군데에 나란히 모아놓기 위해
- 특정 자료 구조 몇 개가 동시에 쓰이고 이들에 대해서 page fault 발생 횟수를 최소로 하
고 싶을 때
- 해당 자료구조를 담은 힙을 할당해 준다.
6. 원하는 작업을 수행하도록 하기 위해
- operator new, delete에서 해주고 싶은 작업이 있으면 자기가 새로 만들어야 한다
Item 51
new 및 delete를 작성할 때 따라야
할
기존의 관례를 잘 알아두자
Item 51 : new 및 delete 관련 관례들
Item 50을 통해 언제 new, delete를 새로 만들어야 할지 알았다.
이번에는 어떻게 만들까의 문제
먼저 operator new의 경우
반환 값 문제
- 요청한 메모리를 마련해 줄 수 있다면 그 메모리에 대한 포인터를 반환
- 마련해 줄 수 없다면 Item 49를 다시 보자
Item 51 : new 및 delete 관련 관례들
- 반환 값을 어떻게 해줄것인가의 문제 말은 쉽다. 구현은?
void * operator new(std : : size_ t size) throw(std : :bad_alloc)
{
using namespace std ;
if (size == 0) {size = 1; } // size 0 일 때도 적법한 주소를 반환해야 한다는 정책 때문에
while (true) { // 무한루프 가능성 있음, new 처리자는 어떤 식으로든 마침표를 찍어야함
if( 할당이 성공했음) { return ( 할당된 메모리에 대한 포인터 ) ; }
// 할당 실패시
new_handler globalHandler = set_new_handler(O) ; // 원래 new 처리자 획득
set_new_handler(global Handler ) ;
If (globalHandler) (*globalHandler) () ; // new 처리자에서 뭔가 해주길 바람
else throw std : : bad_alloc() ; // Item 49의 지향점 부분 참조
}
}
Item 51 : new 및 delete 관련 관례들
operator new는 상속 대상
만약 Base와 Derived의 크기가 다르면?
operator new는 Base의 크기만 할당해줄 뿐이다.
그럴 때는
if(size != sizeof(Base)) // size는 operator new로 전달받은 Derived 클래스의 크기
return ::operator new(size); // 크기가 다르면 기본 new 사용
Item 51 : new 및 delete 관련 관례들
- operator new[]는 웬만하면 하지 말자.
- operator new[]는 상속되어 사용될 수 있다.
- 이 때 operator new[]의 할당 크기를 정할 수 없다.
- 왜냐하면 상속된 클래스의 경우 Base와 크기가 다를수 있기 때문이다.
- 요구되는 바이트 수 / sizeof(Base) 해도 만들기 원하는 객체의 개수가 몇 개인지 알수 없
다
- 그리고 실제로 operator new[]로 전달된 size보다 더 큰 size가 실제 사이즈일 수 있다.
- 배열에서는 앞 뒤로, 필요한 정보를 더 저장해야 하는 경우가 있기 때문이다.
Item 52
위치지정 new를 작성한다면
위치지정 delete도 같이 준비하자
Item 52 : 위치지정 new와 delete의 짝을 맞추자
- 위치지정 new가 뭐죠?
- operator new(std::size_t, + a 매개변수);
- size 뿐만 아니라 +a의 매개변수를 갖는게 위치지정 new이다.
- 왜 이름이 위치 지정인가?
- 보통 operator new(std::size_t, void* memory); 방식으로 많이 쓰였기 때문에
- void* memory로 선언된 곳에 전달된 인자로 메모리 할당을 시작하는 위치를 지정해줬
다
Item 52 : 위치지정 new와 delete의 짝을 맞추자
- 우리가 new를 사용하면 두 가지 함수가 호출된다
- 하나는 메모리 할당 함수이고 하나는 해당 타입의 생성자이다
- 메모리를 할당한 상태인데 생성자에서 오류를 던질 수 있다
- 그러면 런타임 때 메모리를 해제해 줘야한다
- 그런데 이 new가 위치지정 new 였다면?
- 런타임 시스템은 위치지정 new와 똑같은 추가 매개변수 개수와 타입을 갖는 위치지정
delete를 찾는다
Item 52 : 위치지정 new와 delete의 짝을 맞추자
- 그런데 같은 추가 매개변수를 갖는 위치지정 delete가 없다면?
- 여기서 추가라는 말을 쓰는 이유를 다음의 예에서 설명한다
- operator new(std::size_t, std::osstream& logStream)과
operator delete(void* pMemory, std::osstream& logStream)는
같은 추가 매개변수를 갖는다. 즉 std::size_t와 void* pMemory는
new, delete 각각에 기본인 것이다.
- 다시. 추가 매개변수가 짝이 안맞는다면? 아무 일도 안 한다. 즉 메모리는 유실된 상태다.
Item 52 : 위치지정 new와 delete의 짝을 맞추자
- 위치지정 delete는 언제 호출 되는가?
- 기본적으로는 호출되지 않는다
- 위치지정 new에서 오류가 던져졌을 때만 호출된다
- 즉 잘 처리된 객체를 지울 때는 표준 delete가 사용되고 위치지정 new를 사용하는 시점
에
오류가 발생하면 위치지정 delet를 사용하게 된다
Item 52 : 위치지정 new와 delete의 짝을 맞추자
- C++ 전역 유효범위에서 제공하는 operator new의 형태는 다음의 3가지가 표준이다.
- void* operator new(std::size_t) throw(std::bad_alloc); // 기본형
- void* operator new(std::size_t, void*) throw(); // 위치지정형
- void* operator new(std::size_t, const std::nothorw_t&) throw(); // 예외불가
- new를 작성할 때 얘네들을 가리지 않도록 하는 것이 목표!
Item 52 : 위치지정 new와 delete의 짝을 맞추자
- Class 하나에 기본형을 전부 넣어 둔다
- 해당 클래스를 상속 받는다
- using등을 사용해 표준 형태가 내부에서 보이도록 한다
- 그리고 원하는 new를 새롭게 정의한다.
- 그러면 new를 할 때 어떤 인자를 전달하느냐에 따라 표준, 혹은 사용자 지정 new를 사용
할 수 있게 된다.

More Related Content

PPTX
Effective c++chapter1 and2
PPTX
Effective c++chapter4
PPTX
Effective c++chapter3
PDF
Effective c++ chapter 1,2 요약
PPTX
Effective c++ 정리 1~2
PPTX
이펙티브 C++ 공부
PPTX
Effective c++ 정리 chapter 8
PPT
effective c++ chapter 3~4 정리
Effective c++chapter1 and2
Effective c++chapter4
Effective c++chapter3
Effective c++ chapter 1,2 요약
Effective c++ 정리 1~2
이펙티브 C++ 공부
Effective c++ 정리 chapter 8
effective c++ chapter 3~4 정리

What's hot (20)

PPTX
Effective C++ Chaper 1
PPTX
이펙티브 C++ (7~9)
PPTX
Effective c++ 정리 chapter 4
PPTX
이펙티브 C++ 스터디
PPTX
Effective C++ 정리 chapter 3
PPTX
Effective c++ 정리 chapter 6
PPTX
Effective c++ 챕터 2 정리
PPTX
이펙티브 C++ 5,6 장 스터디
PPTX
Effective c++ 1~8장
PDF
More effective c++ chapter1 2_dcshin
PPTX
Effective c++ Chapter1,2
PPTX
Effective c++ 4
PPTX
Effective c++ 1,2
PDF
5 6 1
PDF
Exception&log
PDF
Effective c++ chapter1 2_dcshin
PDF
More effective c++ 항목30부터
PPTX
More effective c++ 2
PDF
Effective c++ chapter3, 4 요약본
PPTX
More effective c++ chapter1,2
Effective C++ Chaper 1
이펙티브 C++ (7~9)
Effective c++ 정리 chapter 4
이펙티브 C++ 스터디
Effective C++ 정리 chapter 3
Effective c++ 정리 chapter 6
Effective c++ 챕터 2 정리
이펙티브 C++ 5,6 장 스터디
Effective c++ 1~8장
More effective c++ chapter1 2_dcshin
Effective c++ Chapter1,2
Effective c++ 4
Effective c++ 1,2
5 6 1
Exception&log
Effective c++ chapter1 2_dcshin
More effective c++ 항목30부터
More effective c++ 2
Effective c++ chapter3, 4 요약본
More effective c++ chapter1,2
Ad

Viewers also liked (20)

PPTX
패킷의 전달과정
PPTX
포인터의기초 (2) - 포인터 사용하기1
PPTX
포인터의 공식
PDF
4. 함수포인터
PPTX
3.포인터
PDF
Memory & object pooling
PPTX
TCP/IP Protocol - JAVA
PDF
Database
PPTX
네트워크 스터디(Tcp 소켓 프로그래밍)
PDF
[네트워크] TCP, 믿을 수 있나요!?
PPTX
뇌자T 1.네트워크와 tcpip
PPTX
포인터의 기초(1)
PDF
Haskell study 15
PDF
Multi thread
PDF
[14.10.20] 아! 그거...모르겠습니다 - TLS(devrookie)
PDF
Tcp ip & io model
PDF
TOAST Meetup2015 - 구름 Cloud IDE (류성태)
PPTX
파이썬 데이터 검색
PPTX
내 질문에는 왜 답변이 달리지 않을까
PDF
소프트웨어 개발자를 위한 하드웨어 상식
패킷의 전달과정
포인터의기초 (2) - 포인터 사용하기1
포인터의 공식
4. 함수포인터
3.포인터
Memory & object pooling
TCP/IP Protocol - JAVA
Database
네트워크 스터디(Tcp 소켓 프로그래밍)
[네트워크] TCP, 믿을 수 있나요!?
뇌자T 1.네트워크와 tcpip
포인터의 기초(1)
Haskell study 15
Multi thread
[14.10.20] 아! 그거...모르겠습니다 - TLS(devrookie)
Tcp ip & io model
TOAST Meetup2015 - 구름 Cloud IDE (류성태)
파이썬 데이터 검색
내 질문에는 왜 답변이 달리지 않을까
소프트웨어 개발자를 위한 하드웨어 상식
Ad

Similar to Effective c++chapter8 (20)

PDF
PPTX
Effective c++ chapter 7,8
PPTX
Chapter7~9 ppt
PDF
7 8 1
PPTX
이펙티브 C++ 789 공부
PDF
Effective c++ chapter7_8_9_dcshin
PPTX
모어 이펙티브 c++ 1,2장 스터디
PPTX
Effective c++(chapter3,4)
PDF
MEC++ 1, 2
PDF
Effective C++ Chapter 1 Summary
PPTX
More effective c++ 1
PPTX
More effective c++ Chap1~2
PDF
M1 2 1
PPTX
Ec++ 3,4 summary
PPTX
C++ 코딩의 정석.pptx
PDF
More effective c++ chapter4 이후 항목 29까지
PDF
[143] Modern C++ 무조건 써야 해?
PPTX
Effective c++ 2
PPT
강의자료4
PPTX
More Effective C++ 4주차
Effective c++ chapter 7,8
Chapter7~9 ppt
7 8 1
이펙티브 C++ 789 공부
Effective c++ chapter7_8_9_dcshin
모어 이펙티브 c++ 1,2장 스터디
Effective c++(chapter3,4)
MEC++ 1, 2
Effective C++ Chapter 1 Summary
More effective c++ 1
More effective c++ Chap1~2
M1 2 1
Ec++ 3,4 summary
C++ 코딩의 정석.pptx
More effective c++ chapter4 이후 항목 29까지
[143] Modern C++ 무조건 써야 해?
Effective c++ 2
강의자료4
More Effective C++ 4주차

Effective c++chapter8

  • 3. 들어가기에 앞서 - 가비지 컬렉터가 없는 C++, 불편하지만 이점도 있다 - 메모리를 수동으로 관리하고 싶다!면 C++! - Operator new, delete 문제, 다중쓰레드에서의 메모리 관리 문제등등! - 이번 챕터를 통해서 해결해보자 - STL 컨테이너와 관련된 메모리 관리도!
  • 4. Item 49 new 처리자(new handler)의 동작 원리를 제대로 이해하자
  • 5. Item 49 : new 처리자의 동작원리를 제대로 이해하자 - operator new를 통해 메모리를 획득하지 못한 경우(즉, 할당할 메모리가 없을 때) - operator new는 예외를 던진다 - 메모리 할당이 제대로 되지 못한 경우, 예외를 던지기 전에 에러 처리 함수를 먼저 호출하게 되어있다 이 에러 처리 함수를 new 처리자(할당 에러 처리자)라 한다 - 표준에는 이 new 처리자를 사용자가 지정해 줄 수 있는 함수가 존재한다 - 바로 set_new_handler
  • 6. Item 49 : new 처리자의 동작원리를 제대로 이해하자 - set_new_handler의 사용 방법 void outOfMem (){ std : : cerr << "Unable to sat isfy r equest for memoryn "; std : : abort ( ) ; } ----------------------------------------------------------------------------------------------------- int main (){ std : : set_ new_ handler (outOfMem) ; // 사용자 정의 new handler 설정 int *pBigDataArray = new int [1 00000000L] ; } 1억개의 정수가 할당되지 못하면? outOfMem이 호출된다. 그리고 std::abort에 의해 프로그램이 종료된다.
  • 7. Item 49 : new 처리자의 동작원리를 제대로 이해하자 - new 처리자 함수의 지향점 1. 사용할 수 있는 메모리를 더 많이 확보하는 쪽 2. 다른 new 처리자를 부르는 쪽 -> 현재의 new 처리자로는 메모리를 할당할 수 없으므 로 3. new 처리자를 제거하는 쪽 -> 바로 예외를 던짐 4. 제거고 뭐고 그냥 예외를 던지는 쪽 5. 프로그램을 끝내는 쪽 - 위 5개 중 한 쪽을 택해 new 처리자를 구현해야 한다.
  • 8. Item 49 : new 처리자의 동작원리를 제대로 이해하자 - 클래스 별로 다른 new 처리자를 만들고 싶다면? ( Widget의 예를 통해 알아 보자) class Widget ( public : static std: :new_handler set_new_handler(std: :new_handler p) throw(); static void * operator new(std: :size_t size) throw(std : : bad_ alloc) ; private : static std::new_handler currentHandler; // static이니 구현은 cpp에서 해준다 } static을 사용하는 이유는 new를 실행하다 실패하면 new_handler를 부르기 때문에 Widget 생성되기 전에 존재해야 한다.
  • 9. Item 49 : new 처리자의 동작원리를 제대로 이해하자 - 클래스 별로 다른 new 처리자를 만들고 싶다면? ( Widget의 예를 통해 알아 보자) class Widget ( public : static std: :new_handler set_new_handler(std: :new_handler p) throw(); static void * operator new(std: :size_t size) throw(std : : bad_ alloc) ; private : static std::new_handler currentHandler; // static이니 구현은 cpp에서 해준다 } static을 사용하는 이유는 new를 실행하다 실패하면 new_handler를 부르기 때문에 Widget 생성되기 전에 존재해야 한다.
  • 10. Item 49 : new 처리자의 동작원리를 제대로 이해하자 - Widget::set_new_handler 구현 부분 std : :new_handler Widget : : set_new_handler(std : :new_handler p) throw() { std : :new_handler oldHandler = currentHandler ; currentHandler = p ; // 원래 표준 set_new_handler처럼 인자를 currentHandler로 설정하고 // old를 반환한다. return oldHandler ; }
  • 11. Item 49 : new 처리자의 동작원리를 제대로 이해하자 Widget만의 operator new 구현하기 위해 new Handler 관리 클래스 선언 class NewHandlerHolder { public : explicit NewHandlerHolder(std : :new_handler nh) : handler(nh) {} ~NewHandlerHolder() { std: :set_new_handler(handler) ; } // 소멸자에서 하는 작업 뒤에서 설명 private : std::new_handler handler; NewHandlerHolder(const NewHandlerHolder&) ; // 복사 막기위해 NewHandlerHolder& operator=(const NewHandlerHolder&); }
  • 12. Item 49 : new 처리자의 동작원리를 제대로 이해하자 Widget만의 operator new 구현 void * Widget : :operator new(std: : size_t size) throw(std : :bad_alloc) { // set_new_handle의 반환 값은 기존의 new 처리자이다. // 따라서 NewHandlerHolder::handler는 기존의 new 처리자를 갖는다 NewHandlerHolder h(std: : set_new_handler(currentHandler)) ; // 표준 할당자로 할당함 return : :operator new(size); } // NewHandlerHolder의 소멸자에서 기존의 new 처리자로 되돌리는 것을 알 수 있다. 이후에는 템플릿으로 만드는 법이 나온다. 이는 다음에 자세히 살피고 이번 Item을 넘어가 자
  • 13. Item 50 new, delete는 언제 바꿀까?
  • 14. Item 50 : custom operator new, delete를 사용하는 경우 1. 잘못된 힙 사용을 탐지하기 위해 - operator new에서 할당된 메모리 주소의 목록을 유지 - operator delete에서 그 목록으로부터 하나씩 제거 - 한 번 new한 객체를 두 번 delete하는 경우가 없게! - overrun(할당된 메모리 블록 끝을 넘어 기록하는 것) - underrun(할당된 메모리 블록을 앞서 기록하는 것) - over,under run 문제 방지
  • 15. Item 50 : custom operator new, delete를 사용하는 경우 2. 효율 향상을 위해 - 컴파일러가 기본으로 제공하는 new, delete는 다양한 요구사항을 맞추기 위해 무난하 게 동작함 - 개발자가 자신에 맞는 동적 메모리 사용 방식을 정확히 안다면 `우수한 성능`의 new, delete 만들기 가능 - 실행속도가 빠르고(최대 10의 n제곱배) 메모리도 적게 차지하는(50%만 사용) 버전 만 들기 가능
  • 16. Item 50 : custom operator new, delete를 사용하는 경우 3. 동적 할당 메모리의 실제 사용에 관한 통계 정보를 수집하기 위해 - 할당되는 메모리 블록의 크기 값들에 대한 정보 - 메모리 할당 순서가 FIFO, LIFO 인지 - 각 실행단계에서의 메모리 블록 할당이 어떻게 이루어지고 있는지 - 등등의 정보를 모으기 위해
  • 17. Item 50 : custom operator new, delete를 사용하는 경우 3. 동적 할당 메모리의 실제 사용에 관한 통계 정보를 수집하기 위해 - 할당되는 메모리 블록의 크기 값들에 대한 정보 - 메모리 할당 순서가 FIFO, LIFO 인지 - 각 실행단계에서의 메모리 블록 할당이 어떻게 이루어지고 있는지 - 등등의 정보를 모으기 위해
  • 18. Item 50 : custom operator new, delete를 사용하는 경우 여기서 잠깐! operator new를 만들 때 주의할 점 : 바이트 정렬(alignment) - 컴퓨터는 대부분의 경우 특정 종류의 메모리 주소를 시작 주소로 하여 저장될 것을 요 구한다 - 무슨 말이고? 만약 4의 배수를 기준으로 각 객체가 저장되어야 한다면 객체들의 시작 주소는 언제나 0, 4, 8 ,c로 끝난다. - 컴퓨터에 따라서 8byte일 수도, 4byte일 수도, 조금 다른 수 일 수 도 있다. - 어떤 아키텍처이냐에 따라 바이트 정렬이 안되면 프로그램이 실행되다가 하드웨어 예 외를 일으킬 수 있다 - x86은 어떤 바이트 단위에 맞추더라도 실행할 수 있지만 8바이트 단위로 정렬하면 런타 임 접근속도가 훨씬 빨라진다
  • 19. Item 50 : custom operator new, delete를 사용하는 경우 4. 할당 및 해제 속력을 높이기 위해 - 기본 제공 new는 느린 경우도 많다 - 특정 크기를 할당할 일이 많으면 직접 만들어 속도에서 향상을 만들어 낼 수 있다
  • 20. Item 50 : custom operator new, delete를 사용하는 경우 5. 임의의 관계를 맺고 있는 객체들을 한 군데에 나란히 모아놓기 위해 - 특정 자료 구조 몇 개가 동시에 쓰이고 이들에 대해서 page fault 발생 횟수를 최소로 하 고 싶을 때 - 해당 자료구조를 담은 힙을 할당해 준다. 6. 원하는 작업을 수행하도록 하기 위해 - operator new, delete에서 해주고 싶은 작업이 있으면 자기가 새로 만들어야 한다
  • 21. Item 51 new 및 delete를 작성할 때 따라야 할 기존의 관례를 잘 알아두자
  • 22. Item 51 : new 및 delete 관련 관례들 Item 50을 통해 언제 new, delete를 새로 만들어야 할지 알았다. 이번에는 어떻게 만들까의 문제 먼저 operator new의 경우 반환 값 문제 - 요청한 메모리를 마련해 줄 수 있다면 그 메모리에 대한 포인터를 반환 - 마련해 줄 수 없다면 Item 49를 다시 보자
  • 23. Item 51 : new 및 delete 관련 관례들 - 반환 값을 어떻게 해줄것인가의 문제 말은 쉽다. 구현은? void * operator new(std : : size_ t size) throw(std : :bad_alloc) { using namespace std ; if (size == 0) {size = 1; } // size 0 일 때도 적법한 주소를 반환해야 한다는 정책 때문에 while (true) { // 무한루프 가능성 있음, new 처리자는 어떤 식으로든 마침표를 찍어야함 if( 할당이 성공했음) { return ( 할당된 메모리에 대한 포인터 ) ; } // 할당 실패시 new_handler globalHandler = set_new_handler(O) ; // 원래 new 처리자 획득 set_new_handler(global Handler ) ; If (globalHandler) (*globalHandler) () ; // new 처리자에서 뭔가 해주길 바람 else throw std : : bad_alloc() ; // Item 49의 지향점 부분 참조 } }
  • 24. Item 51 : new 및 delete 관련 관례들 operator new는 상속 대상 만약 Base와 Derived의 크기가 다르면? operator new는 Base의 크기만 할당해줄 뿐이다. 그럴 때는 if(size != sizeof(Base)) // size는 operator new로 전달받은 Derived 클래스의 크기 return ::operator new(size); // 크기가 다르면 기본 new 사용
  • 25. Item 51 : new 및 delete 관련 관례들 - operator new[]는 웬만하면 하지 말자. - operator new[]는 상속되어 사용될 수 있다. - 이 때 operator new[]의 할당 크기를 정할 수 없다. - 왜냐하면 상속된 클래스의 경우 Base와 크기가 다를수 있기 때문이다. - 요구되는 바이트 수 / sizeof(Base) 해도 만들기 원하는 객체의 개수가 몇 개인지 알수 없 다 - 그리고 실제로 operator new[]로 전달된 size보다 더 큰 size가 실제 사이즈일 수 있다. - 배열에서는 앞 뒤로, 필요한 정보를 더 저장해야 하는 경우가 있기 때문이다.
  • 26. Item 52 위치지정 new를 작성한다면 위치지정 delete도 같이 준비하자
  • 27. Item 52 : 위치지정 new와 delete의 짝을 맞추자 - 위치지정 new가 뭐죠? - operator new(std::size_t, + a 매개변수); - size 뿐만 아니라 +a의 매개변수를 갖는게 위치지정 new이다. - 왜 이름이 위치 지정인가? - 보통 operator new(std::size_t, void* memory); 방식으로 많이 쓰였기 때문에 - void* memory로 선언된 곳에 전달된 인자로 메모리 할당을 시작하는 위치를 지정해줬 다
  • 28. Item 52 : 위치지정 new와 delete의 짝을 맞추자 - 우리가 new를 사용하면 두 가지 함수가 호출된다 - 하나는 메모리 할당 함수이고 하나는 해당 타입의 생성자이다 - 메모리를 할당한 상태인데 생성자에서 오류를 던질 수 있다 - 그러면 런타임 때 메모리를 해제해 줘야한다 - 그런데 이 new가 위치지정 new 였다면? - 런타임 시스템은 위치지정 new와 똑같은 추가 매개변수 개수와 타입을 갖는 위치지정 delete를 찾는다
  • 29. Item 52 : 위치지정 new와 delete의 짝을 맞추자 - 그런데 같은 추가 매개변수를 갖는 위치지정 delete가 없다면? - 여기서 추가라는 말을 쓰는 이유를 다음의 예에서 설명한다 - operator new(std::size_t, std::osstream& logStream)과 operator delete(void* pMemory, std::osstream& logStream)는 같은 추가 매개변수를 갖는다. 즉 std::size_t와 void* pMemory는 new, delete 각각에 기본인 것이다. - 다시. 추가 매개변수가 짝이 안맞는다면? 아무 일도 안 한다. 즉 메모리는 유실된 상태다.
  • 30. Item 52 : 위치지정 new와 delete의 짝을 맞추자 - 위치지정 delete는 언제 호출 되는가? - 기본적으로는 호출되지 않는다 - 위치지정 new에서 오류가 던져졌을 때만 호출된다 - 즉 잘 처리된 객체를 지울 때는 표준 delete가 사용되고 위치지정 new를 사용하는 시점 에 오류가 발생하면 위치지정 delet를 사용하게 된다
  • 31. Item 52 : 위치지정 new와 delete의 짝을 맞추자 - C++ 전역 유효범위에서 제공하는 operator new의 형태는 다음의 3가지가 표준이다. - void* operator new(std::size_t) throw(std::bad_alloc); // 기본형 - void* operator new(std::size_t, void*) throw(); // 위치지정형 - void* operator new(std::size_t, const std::nothorw_t&) throw(); // 예외불가 - new를 작성할 때 얘네들을 가리지 않도록 하는 것이 목표!
  • 32. Item 52 : 위치지정 new와 delete의 짝을 맞추자 - Class 하나에 기본형을 전부 넣어 둔다 - 해당 클래스를 상속 받는다 - using등을 사용해 표준 형태가 내부에서 보이도록 한다 - 그리고 원하는 new를 새롭게 정의한다. - 그러면 new를 할 때 어떤 인자를 전달하느냐에 따라 표준, 혹은 사용자 지정 new를 사용 할 수 있게 된다.