1. 핵심 개념
- const, constexpr, consteval(cpp20)
- reference 타입
- 함수 오버로딩 우선 순위: 정확한 매칭 -> 타입 승격 반환 -> 표준 타입 반환 -> 사용자 정의 타입 변환
- 승격: 값이 손실나지 않는 방향으로 타입 캐스팅
- 템플릿 문법(공변, 반공변성? 타입제약?, 구현은 컴파일 타임?)
- STL 사용법(vector, map, container, algorithm, iterator); 언제 한 번 정리하기 + sort의 comp(a, b)
- explicit는 컴파일러가 원하지 않는 암시적 형변환을 수행하지 못하도록 제한하는 키워드; 인자가 하나인 생성자에는 기본적으로 붙이는 것을 권장함(매개변수에 클래스를 받을 때 생성자에 따라서 자동으로 사용자 정의 타입으로 캐스팅해서 사용되는 경우가 있음)
2. 상세 내용
2.0. NRVO
객체를 리턴해야 하는 메서드를 구현할 때 굳이 call by reference를 사용하여 객체를 할당하지 않아도 컴파일러가 불필요한 복사를 막기 위해 최적화(NRVO)를 해준다.
#include <iostream>
class BigData {
public:
BigData() { std::cout << "Default Constructor\n"; }
BigData(const BigData&) { std::cout << "Copy Constructor (Expensive!)\n"; }
BigData(BigData&&) noexcept { std::cout << "Move Constructor\n"; }
// 이동 생성자가 명시적으로 선언되었기 때문에,
// 컴파일러가 안전을 위해 기본 복사/이동 대입 연산자의 생성을 암묵적으로 삭제해서 테스트를 위해 재정의
BigData& operator=(const BigData&) {
std::cout << "Copy Assignment\n";
return *this;
}
BigData& operator=(BigData&&) noexcept {
std::cout << "Move Assignment\n";
return *this;
}
};
// 1. 기존의 Out-parameter 방식
void createData_ByRef(BigData& outTarget) {
std::cout << " [Inside createData_ByRef]\n";
outTarget = BigData(); // 임시 객체 대입 -> Move Assignment 호출
}
// 2. 권장되는 Return by Value 방식 (RVO/NRVO)
BigData createData_ByValue() {
std::cout << " [Inside createData_ByValue]\n";
BigData temp;
return temp; // RVO 적용 시 복사/이동 생략
}
int main() {
std::cout << "--- 1. Out-parameter Test ---\n";
BigData target; // Default Constructor
createData_ByRef(target);
std::cout << "\n--- 2. Return by Value Test ---\n";
BigData result = createData_ByValue(); // Default Constructor (RVO 적용됨)
return 0;
}
// 예상 출력
// Default Constructor
// [Inside createData_ByRef]
// Default Constructor
// Move Assignment
//
// -- - 2. Return by Value Test-- -
// [Inside createData_ByValue]
// Default Constructor
출력 결과를 보면 리턴값으로 객체를 반환하는 메서드에서 컴파일러가 NRVO(Named Return Value Optimization)를 해서 결과적으로 call by reference로 할당한 쪽보다 더 효율적이게 객체를 할당 받았다.
2.1. const
constant로 프로그램 실행 중 값이 변경되지 않도록 대상을 선언할 때 사용하는 키워드다.
상수로써 사용
const int versionNumberMajor { 1 };
cpp에서는 #define 대신에 const를 붙여 상수로 사용한다.
const pointer
const가 붙는 위치에 따라 변수가 지닌 메모리 주소가 상수인지, 변수가 가리키는 값이 상수인지 지정할 수 있다.
const를 읽는 방법은 기본적으로 오른쪽에서 왼쪽으로 읽으면 된다. [[TIL260427]]에서 다룬 Right-Left Rule을 기억하면서 변수를 읽어보자.
int a = 5;
int b = 7;
// ptr1, 2 is pointer to constant integer
int const * ptr1 { &a };
const int* ptr2 { &a }; // 이렇게 왼쪽에 쓰일 수도 있으니 해석의 주의하자.
// *ptr1 = 1; // 컴파일 에러
// ptr3 is constant pointer to integer
int* const ptr3 { &a };
// ptr3 = &b; // 컴파일 에러
// ptr4 is constant pointer to constant integer
const int* const ptr4 { &a };
// *ptr4 = 1; // 컴파일 에러
// ptr4 = &b; // 컴파일 에러
const parameter
cpp에서는 비 const 변수를 const 변수로 캐스팅할 수 있다. const 매개변수를 받도록 지정하면 전달 받은 매개변수를 변경하려 할 때 컴파일 에러가 발생한다.
void test(const std::string* someString){
*someString = "test"; // 컴파일 에러 발생
}
const method
const는 클래스 메서드에도 지정이 가능하다. const가 지정된 메서드는 해당 클래스의 데이터 멤버를 수정할 수 없다.
class a{
public:
void someInspector() const; // 내부에서 a 같은 데이터 멤버 수정하려 할 때 컴파일 에러
private:
int a;
}
[!NOTE] const-correctness principle
객체의 데이터 멤버를 변경하지 않는 멤버 함수는 const로 선언하는 것이 좋다. 이런 멤버 함수를 'inspector'라고 부른다.(비 conste 멤버 함수는 'mutator'라고 부름)
constexpr
함수에 붙일 수 있는 키워드로 constexpr 키워드를 붙이면 컴파일 시간에 평가될 수 있다. constexpr이 붙은 함수는 컴파일 시간에 실행될 수 있어야 하기 때문에 제약 사항이 붙는다. 비 constexpr 함수 호출 불가능하고 side effect가 없는 함수여야 한다.(exception 불가)
consteval
앞선 constexpr은 런타임 시간에도 호출이 될 수 있다. 하지만 consteval 키워드를 사용하면 해당 함수를 immediate function으로 만들어 반드시 컴파일 시간에 실행하도록 한다.
2.2. reference type(&)
cpp에서 레퍼런스(referece)는 변수에 대한 별칭(alias)이다. 초기화하지 않으면 컴파일 에러가 발생하며, 한 번 설정되었다면 변경이 불가능하다. 그리고 레퍼런스에 대한 레퍼런스를 설정하는 것도 불가능하다.
레퍼런스를 설정할 때는 int& aRef = &a;와 같이 참조 연산자로로 넘겨주지 않고 int& aRef = a;와 같이 넘겨주면 된다.
레퍼런스도 const 키워드를 붙일 수 있다. 또한 포인터에 대한 레퍼런스도 설정 가능하다.
int a = 5;
const int& aRef { a }; // aRef is reference to constant integer
int* aPtr = &a;
int*& aPtrRef = aPtr; // aPtrRef is reference to pointer to integer
주의할 점은 레퍼런스는 포인터와 타입이 다르기 때문에 타입 매칭 시 컴파일 에러가 발생할 수 있다.
int x = 3;
int& xRef { x };
int* xPtr { &x };
return xRef == xPtr // 컴파일 에러! xPtr == &xRef 같이 사용해야 함
2.3. Move semantics
3. 질문 및 해결 (Q&A)
- 함수 시그니처 까먹음; 그리고 왜 반환타입은 오버로딩에 영향 x?
4. 관련 문서 (Links)
'내일배움캠프 > TIL' 카테고리의 다른 글
| TIL260512 - Unreal (0) | 2026.05.12 |
|---|---|
| TIL260511 - Unreal (0) | 2026.05.11 |
| TIL260507 - Quaternion (0) | 2026.05.07 |
| TIL260506 - Quaternion (0) | 2026.05.06 |
| TIL260504 - Quaternion (0) | 2026.05.04 |