double()을 구현했을 때의 문제점
SpreadsheetCell cell { 6.6 };
double d1 { cell + 3.3 }; //컴파일 에러!
이유는?
cell이 double() 을 통해 형변환 되어 덧셈이 될지
3.3이 double 생성자를 통해 임시객체가 되어 덧셈이 될지
컴파일러가 정할 수 없기 때문
생성자 앞에 explicit 키워드를 지정해서 자동 형변환이 일어날때 이 생성자를 사용하지 않게 할 수 있다
다만 형변환으로 객체가 생성되는 기능은 매우 편리하기 때문에 막기엔 좀 그렇다
그래서 C++11 부터는 double 변환 연산자를 explicit으로 선언해서 생성자쪽으로 연산되도록 할 수 있다
15.8.3 부울 표현식으로 변환
객체를 부울 표현식에서 사용하면 좋을 때가 있다
if(obj) ...
if(!obj) ...
operator void*() //앞선 포인터 객체에선 포인터를 직접 반환하게 하면 됨
operator bool() // 이렇게 해도 됨
if (p != nullptr) //에러
p 객체가 bool() 오버로딩이 되어있더라도 nullptr은 0(false) 가 아니기 때문에 당연히 에러
bool operator!=(const Pointer<T>& lhs, std::nullptr_t rhs); // null_ptr에 대한 비교 수행 가능
if (p != NULL) //에러!
null_ptr은 0이 아니지만
0은 null_ptr 취급될 수 있다
NULL은 0또는 0L(null)로 취급되므로 위 조건식은 p != 0으로 취급된다
그러므로 0을 정수 0으로 취급할지 null_ptr로 취급해서 오버로딩한 !=를 타야 할지 컴파일러는 알 수 없다
bool()을 정의하면 생기는 또 다른 문제
Pointer<SpreadsheetCell> anotherSmartCell { new SpreadsheetCell { 5.0 } };
int i { anotherSmartCell };
int i에 대입할때 형변환이 일어나는데 bool도 어쨋든 0,1의 int값이 될 수 있으므로 정의된 bool() 오버로드를 먼저 타버림
그리고 int로 형변환이 일어나 결론적으로 i에는 0 또는 1 값밖에 안들어감
그래서 다들 void* 오버로드를 선호함
15.9 메모리 할당 및 해제 연산자 오버로딩
작은 객체를 여러번 할당 해제하는 과정에서 발생하기 쉬운 메모리 파편화를 방지하기 좋음
new 할때마다 메모리를 할당하는 대신 미리 만들어놓은 메모리 풀에서 객체를 꺼내 쓰도록 구현할 수 있음
new 표현식
operator new를 호출해서 객체에 대한 메모리 공간을 할당 -> 객체의 생성자 호출
-> 객체에 대한 포인터 리턴
delete 표현식
cell 소멸자 호출 -> operator delete 호출 -> 메모리 해제
new delete를 오버로드 하면 메모리 할당과 해제 과정을 직접 제어할 수 있지만 표현식 자체를 오버로드 할 수는 없다.
즉 실제로 메모리를 할당하고 해제되는 과정은 커스터마이즈 할 수 있지만 생성자와 소멸자를 호출하는 동작은 변경 불가!
new 오버로딩 6종류
전부 다른 new 오버로드니 주의
# new(nothrow) <- new로 할당하고 실패하면 예외 대신 nullptr 던짐
나머지 두개는 할당 작업 없이 기존에 할당된 객체의 생성자만 호출하는 특수한 형태의 new
배치 new 연산자
기존에 확보된 메모리에서 객체를 생성 가능
하지만 이 둘은 오버로딩이 금지됨
delete의 6가지 오버로딩
delete는 사용하는 방식이 사실 delete delete[] 두가지 뿐. delete (nothrow)는 없기 때문
c++에서 delete가 실패했을 경우 어떻게 되는지에 대한 정의가 없기 때문에 절대로 예외를 던지면 안되는 연산임
하지만 오버로딩은 6가지임
delete 오버로딩의 nothrow 버전은 생성자에서 익셉션이 발생할 때만 사용됨
배치 버전의 delete도 아무런 작업 X. 배치 버전의 new가 애초에 메모리 할당을 하지 않기 때문
15.9.2 글로벌 버전의 new delete 오버로딩
프로그램 자체에서 new delete를 재정의
클래스에서 이보다 구체적인 오버로딩이 되어있으면 그 버전을 호출
# 쓰지마!!
new를 재정의 했다면 반드시 그에 대응되는 delete도 재정의 해야한다
메모리 할당의 일관성을 유지하기 위해 new 한종류를 오버로딩 하면 다른 6가지 모두 오버로드 해주는게 좋다
명시적으로 원하지 않는 버전의 new 오버로드를 막을 수도 있고
new에 매개변수를 받도록 오버로드 할 수도 있다
15.10 사용자 정의 리터럴 연산자
이건 좀;;
823p
'전문가를 위한 C++' 카테고리의 다른 글
2025/04/07 ch.17 반복자와 범위 라이브러리 (0) | 2025.04.07 |
---|---|
2025/04/06 ch.16 C++ 표준 라이브러리 둘러보기 (0) | 2025.04.07 |
2025/03/27 ch.15 연산자 오버로딩 (0) | 2025.03.27 |
2025/03/26 ch.15 연산자 오버로딩 (0) | 2025.03.26 |
2025/03/25 ch.14 에러처리 (0) | 2025.03.25 |