: Car 클래스 만들고, 생성자와 소멸자를 정의하라.
1) Car * p 를 operator new 연산자로 할당하고,
2) cout << "hello " << endl 출력하고
3) placement new 로 생성자 호출하고
4) 소멸자를 명시적으로 호출하고
5) 메모리를 명시적으로 해지하라 . : operator delete 연산자
아래 내용을 공부하면서 정리
할당 하는 방법 -> operator new (sizeof ( 모든 type ) )
해지 하는 방법 -> operator delete (sizeof ( 모든 type ) )
: 재정의함수를 만들 때는 호출하는 코드를 생각하면서 , 역으로 작성하면됨.
- 보통 Point p = new Point(); 를 하는 거니까. 이 때 new 연산자는 Point 클래스를 반환함.
: 그런데 이거는 c++ 에서 우리에게 편하게 사용하라고 하는 거고 결국에는
malloc 의 반환처럼 void 타입을 반환함.
-> void * operator new(sizeof( Point))
: sizeof를 size_t 로 변경
: 메모리만 할당함.
- 메모리를 먼저 할당함. : operator new() 연산자 함수를 사용함.
- 생성자를 호출함. : new (&p) Point(생성자 인자.)
- 메모리 주소를 해당 타입으로 반환함. : static_cast 사용
- 소멸자를 먼저 호출함.
: 객체의 멤버 데이터를 먼저 지워야 하잖아.- 객체의 메모리를 해지함.
: operator delete() 사용
- 동적할당할 때만 사용하자.
- 메모리만 할당하게 됨.
- 클래스를 대상으로 하더라도 반환값은 void * 형임.
-> 반드시 static_cast를 사용해 형변환해야 함.
operator new (sizeof(클래스명))
static_cast< 클래스명> ( operator new (sizeof(클래스명)) )
- 메모리를 해제하는 부분임.
- 소멸자를 부르지는 않음.
operator delete( 객체 명 );
: operator new() 연산자 함수를 활용해 객체 Point p 를 동적할당하라.
-> 결과 : 생성자는 호출되지 않을 것임.
operator new동적할당과 일반 동적할당. 정적할당의 차이점.
- operator new 동적할당
: 멤버 내에서 초기화를 했지만, 초기화 이루어지지 않음.
-> 생성자를 호출하지 않았고, 클래스 내로 진입하지도 않음.
- 일반 new 동적할당.
: 초기화 이루어짐.
-> 컴파일러가 내부적으로 클래스를 진입했다는 것임.
- 정적할당
: 초기화 이루어짐.
결론
: 유저가 직접 new 연산자를 사용할 경우, 명시적으로 생성자를 호출해야 함.
: 위에서 operator new(sizeof(Point))를 호출한 내용을 토대로
오버로딩을 만들면 됨
: malloc 할 것을 해제하므로, free 사용.
:: noexcept를 사용해야 함.
-> 자원 해제시에 예외 처리 발생하면 , 메모리 누수 발생하기 때문임.
new 연산자는 재정의할 수 없음. / operator new는 재정의가 가능함.
인자의 갯수를 다르게 만들 수 있음.
하지만 첫번째 인자는 반드시 size_t로 받아야 함.
-> 결과 : 위와 같이 호출하는 부분은 new 바로 다음에 괄호를 통해 호출할 수 있음...
도대체 왜 new 할당을 분류해서 사용하는 것일까...?
다음 시간에..
new (객체의 주소) 클래스명
: 포인터로 만들었을때, 이렇게 하면 안됨..
-> 이렇게 하면, 포인터의 주소인데,,,
: 생성자를 명시적으로 호출하는 방법.
:: 기존에 만들어진 객체를 이용해 생성자를 호출함.
작성하는 방법.
new( 객체의 주소 ) 클래스명
예시
: 밑의 그림을 보면, operator new 함수에서 메모리를 할당하지는 않았지만,
기존에 만들어져 있는 p라는 객체를 이용해 생성자를 호출하고 있는 것을
확인할 수 있음.
결과
c++ 표준에 있음.
결론
: operator new 연산자로 동적할당 했을 때만 placement new 를 사용하자.
아래 예시
: 메모리를 새롭게 할당하라고 하는 것이 아닌, 생성자를 다시 한번
호출하라고 하는 코드임.
: 객체.~소멸자();
: Point 클래스를 만들고, 소멸자, 생성자 만들고, operator new 함수, operator delete 함수 만들자.
:: 그리고 호출하는 부분에서 동적으로 *p를 선언하고 operator new로 메모리를 할당하고, placement new로 생성자를 호출하고,
::: 소멸자를 직접 호출하고, 객체의 메모리를 해지하라.
: 생성자 호출이 더 큰 역할을 함.
네트워크에 접속
db 연결
그림의 주석 내용을 보자!
이점 : 메모리 관리측면이 아닌, 초기화 시 db연결 등 다른 객체와의 설정등을
하는 생성자 호출을 유저가 원하는 순간에 할 수 있음!
도대체 왜 이러한 짓을 하는 거지???
: 메모리와 생성자를 분리해서 따로 관리하기 위함.
디폴트 생성자가 없는 클래스의 경우, 객체는 한개만 만들수 있음.
디폴트 생성자가 없는 클래스에서 10개의 객체를 만들고 싶을 때
불가능함! , 디폴트가 없어서 불가능한 상황임.
-> 이 때 메모리 생성과 생성자 호출을 분리하는 방법으로 해결이 가능함.
vector의 내부 동작
vectorv(10, Point(0,0)) ;
1) 10개의 메모리를 먼저 할당함.
2) Point(0,0) 클래스의 복사생성자를 받아서 생성자를 호출함.
1) db에 10개 연결하는 코드가 있음.
: 메모리를 10개 만들어 놓음.
2) resize로 7개로 줄인다고 한다면? ,
: 메모리는 줄어들지는 않지만, 3개의 연결된 상태는 끊어야 함!
-> 3개의 소멸자를 불러서 연결을 끊자!
--> resize하고 난후의 소멸자가 3개 호출되는 것을 확인할 수 있음.
이때는 delete 를 호출하는 것이 아니라, 명시적으로 소멸자를 호출해야 함.
~p1.Point();
3) size를 8로 변경한다면? 1개의 db 연결을 해야함.
-> resize(8) 이후에 생성자가 1개 호출되는 것을 확인할 수 있음.
결과 : 벡터의 resize의 경우, 작은 값으로 줄인다면, 메모리는 줄어들지 않지만, 소멸자가 호출되는 것을 확인할 수 있음.
결론
: 소멸자는 명시적으로 호출되어야 함.
-> stl의 vector의 resize는 이를 이용하고 있음.