2020 이전/C++

C++의 까다롭고 유별난 친구들

이상해C++ 2019. 3. 13. 21:56

전문가를 위한 C++ 10강 공부 요약



참조형: 참조는 다른 변수에 대한 alias(별명)

참조형 변수는 항상 생성시점에 초기화해야한다.( 멤버 변수인경우 클래스 생성자 초기화 리스트에서 초기화 되어야한다. )


참조와 포인터의 선택 기준.


1. 포인터와 달리 참조는 유효하지 않는 데이터를 가리키는 것이 거의 불가능한다.

2. 역참조 연산을 할 일이 없으므로 포인터를 사용하면 접할 수 있는 역참조 오류를 볼 일이 없다.

3. 참조형 파라미터로는 디폴트 값을 지정할 수 없다. 포인터는 파라미터에서 nullptr과 같은 디폴트값 지정 가능

4. 해당 메모리를 누가 소유하고 있는가. 변수를 넘겨받는 측이 객체와 관련한 메모리를 해제해야한다면 포인터를 사용,


포인터를 사용해야하는 유일한 상황은 가리키는 대상을 바꾸어야 할 때(참조형 변수는 초기화 되고 나면 가리키는 대상을 변경할 수 없다. 가리키는 대상의 "값"은 변경 가능하다)




우측값 참조

C++에서의 좌항: 그 주소를 얻을 수 있거나 변수 이름을 가진 대상

우항: 좌항이 아닌 것


우측값 참조(rvalue reference)

대입문 오른쪽에 오는 값에대한 참조로, 특히 우항이 임시객체일 떄 적용되는 개념이다.

우측값 참조는 임시 객체가 생성되는 코드 구문에서 함수나 메서드, 특히 복제 생성자나 대입 연산자를 컴파일러가 선택할 때 사용된다. 삭제될 예정인 크기가 큰 임시 객체를 복제해야할 때 전체 데이터를 깊게 복제하지 않고 포인터 주소만 얕게 복제하여 오버헤드를 줄이는데 목적이 있다.


우측값 참조형 파라미터는 선언할 때 &&를 붙인다. ex) int&& value





키워드


const 키워드


const로 표시된 변수는 컴파일러에 의해 모니터링 되어 변경 시도 시 에러를 발생시킨다. 또한 컴파일러 최적화 때, 해당 변수가 변경되지 않는 다는 사실을 참조하여 컴파일러는 더 나은 코드를 만들어 낼 수 있다.


const 파라미터, const 변수: 변경되지 말아야 할 변수, 또는 파라미터가 있다면 const를 통하여 보호할 수 있다.

겁나 헷갈리는 const 포인터. 



const는 (보통) 자신의 왼쪽에 오는 대상에 적용 된다.


const 참조는 보통 파라미터로 사용되는데 단순히 성능의 최적화를 목적으로 참조형 파라미터를 사용했다면 의도하지 않게 함수 안에서 변경되는 것을 막기위해 const를 사용한다.


const 클래스 메서드: 클래스 메서드를 const로 선언하면 그 함수안에서는 클래스 맴버 데이터 중 mutable로 선언된 것을 제외하고 그 값을 변경할 수 없다. const 메서드는 객체에 변경을 가할 수 없다. 


constexpr 키워드


상수 표현식을 요구하는 곳에는 변수와 값을 리턴하는 함수를 쓸 수 없지만, constexpr 키워드를 붙이면 메서드는 상수표현식이 된다. 상수 표현식은 컴파일 타임에 계산되기 때문에 쓸 수 있다.




1. 함수를 constexpr로 선언하기 위해서는 컴파일러가 컴파일 타임에 계산 완료할 수 있어야한다.

2. 함수의 본체는 한 개의 리턴문으로 만들어져야 한다.(다른 cosntexpr 호출 가능)

3. 함수의 리턴타입은 반드시 리터럴 타입(문자 상수로 표현가능한 char[], float, int 등 내장 타입 데이터)을 반환 해야한다.

4. constexpr로 선언하는 대상이 클래스의 메서드일 경우 그 메서드는 virtual로 선언될 수 없다.

5. 함수인자는 리터럴 타입이여야한다.

6. constexpr은 템플릿이나 매크로처럼 호출 이전에 이미 컴파일러가 구현부를 알 수 있어야한다.

7. new/delete를 허용 하지 않는다.


static 키워드

1. 스태틱 데이터 멤버와 스태틱 메서드

클래스의 데이터 멤버와 메서드는 static으로 선언할 수 있다. static으로 선언된 데이터 멤버는 클래스 수준에서 단 하나만 존재한다. static 메서드 또한 클래스 수준으로 존재하여 특정 객체에 종속되어 호출되지 않는다. 특정 객체에 종속되지 않기 때문에 일반 멤버 데이터를 static 메서드 안에서 쓸 수 없다.


2. static 링킹

오브젝트 파일을 link할 때 같은 파일 안에서 연결되는 것을 내부 링킹(static 링킹), 다른 외부 파일과 연결되는 것을 외부 링킹이라고 한다.



첫번째 경우 A.cpp는 B의 있는 구현부와 선언부가 링킹되지만 static으로 선언하면 내부 링크만 허용하겠다는 뜻으로

두번째 경우에서 A.cpp는 구현부를 찾을 수 없게 된다.


static을 쓰는 대신 이름없는 네임 스페이스로 감싸도 똑같이 내부 링킹이 가능하다.


외부 링킹(extern 키워드)

extern 키워드는 static과 다르게 명시적으로 외부 링킹할 대상을 선언한다. const, typedef는 기본적으로 내부 링킹이지만 extern 키워드로 외부링킹이 적용되게 바꿀 수 있다. extern키워드를 붙이는 순간 컴파일러는 해당 코드를 정의가 아니라 선언으로 취급하여 메모리를 할당하지 않는다. 그러므로 extern없이 별도로 선언을 한 번 더 해야한다.


3. 함수 내 static 변수

함수 리턴후에도 계속 lifetime이 유지되는 static 로컬변수는 특정 함수 안에서만 접근가능하는 전역 변수와 같다. 


로컬 변수가 아닌 변수들의 초기화/소멸 순서


1. global 변수, static 클래스 데이터 멤버 변수들은 main()함수가 실행되기 전에 초기화가 이루어진다. 

2. 같은 파일 내부의 non local 변수들끼리는 선언된 순으로 초기화 되지만 다른 파일끼리는 순서가 정해져 있지 않다.

3. 소멸 순서또한 같은 파일 내부에서는 선언 반대 순으로 소멸되고 다른 파일끼리는 순서가 정해져 있지 않다.


타입과 캐스팅


typedef

타입에 대한 alias를 생성해준다고 생각하면 된다.(엄연히 타입 알리어스는 아니지만) 스코프 지정자를 포함할 수 있다.


type alias

using MyInt = int (=typedef int MyInt)

하지만 타입 alias는 템플릿에서 typedef 그 이상의 역할을 한다.


캐스팅

1. const_cast

const 변수의 상수 속성을 없애는 악마의 캐스팅이다. 금단의 지식


2. static_cast

정상적으로 허용되는 타입간 변환을 명시적으로 쓰고싶을때, 그리고 보통 다운캐스팅을 할 때 사용한다. 스태틱 캐스트는 런타임 타입 검사를 하지 않는다. static_cast로 다운캐스팅, 업캐스팅 둘다 가능하지만 그것이 런타임에 유효한지는 검사하지 않는다. 


3. reinterpret_cast

static_cast 보다 강력하고 위험한 캐스팅방법. C++에서 통상적으로 허용되지 않지만 프로그래머가 의도한다면 강제로 타입변환을 수행한다. void*와의 상호 변환이 가장 대중적이다. 관계있는 클래스 참조 타입은 static_cast, 관계없는 클래스 참조 타입은 reinterpret_cast.


4. dynamic_cast

dynamic_cast는 클래스 계층에 대해 런타임 타입정보(RTTI) 검사를 수행하여 해당 변환이 적합한 클래스 계층간 이동인지 확인한다. 캐스팅이 부적합 한 경우 null 포인터 또는 bad_cast 익셉션을 발생시킨다. 


런타임 타입 정보는 객체의 vtable에 저장된다. 이 때문에 dynamic_cast가 타입 검사를 하기위해서는 클래스에 적어도 하나 이상의 virtual 메서드가 있어야한다. vtable이 없으면 dynamic_cast를 사용할때 에러가 난다. 


'2020 이전 > C++' 카테고리의 다른 글

해시 버켓 사이즈 비교 실험  (0) 2019.07.06
C++의 까다롭고 유별난 친구들2  (0) 2019.03.22
C++ 함수포인터 넘겨줄 때 명시적 형식이 없습니다  (0) 2019.02.21
C++ std::function 콜백  (0) 2019.02.06
C++ auto  (0) 2018.11.28