현대적 C++
1. auto, decltype, nullptr
C++11부터 제공되는 `auto`, `decltype`, `nullptr`는 코드의 가독성과 효율성을 높여줍니다.
1.1. auto
`auto`는 변수의 타입을 컴파일러가 자동으로 추론하도록 도와줍니다. 이를 통해 타입을 명시적으로 선언하지 않아도 됩니다.
#include <iostream>
int main() {
auto x = 5; // int 타입으로 자동 추론
auto y = 3.14; // double 타입으로 자동 추론
std::cout << x << ", " << y << std::endl;
return 0;
}
1.2. decltype
`decltype`는 변수나 표현식의 타입을 가져오는 키워드입니다. 이는 특히 복잡한 타입을 다룰 때 유용합니다.
#include <iostream>
int main() {
int x = 10;
decltype(x) y = 20; // x의 타입과 동일한 int 타입
std::cout << y << std::endl;
return 0;
}
1.3. nullptr
`nullptr`는 `NULL`을 대체하는 키워드로, 포인터가 유효하지 않음을 명시적으로 표현합니다.
#include <iostream>
int main() {
int* ptr = nullptr; // nullptr로 초기화
if (ptr == nullptr) {
std::cout << "포인터는 null입니다." << std::endl;
}
return 0;
}
2. 람다 함수, 범위 기반 for문
C++11에서 도입된 람다 함수와 범위 기반 for문은 코드의 간결함과 효율성을 크게 향상시켰습니다.
2.1. 람다 함수
람다 함수는 코드 내에서 즉석에서 정의하고 사용할 수 있는 익명 함수입니다. `[]` 안에 캡처할 변수를 지정하고, `()`로 인자를 받으며, `{}` 안에 함수 내용을 작성합니다.
#include <iostream>
int main() {
auto add = [](int a, int b) { return a + b; };
std::cout << add(3, 4) << std::endl;
return 0;
}
2.2. 범위 기반 for문
범위 기반 for문은 컨테이너를 반복할 때 편리하게 사용할 수 있습니다. C++11부터 추가된 기능으로, 다음과 같이 사용합니다.
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
for (auto& element : v) {
std::cout << element << " ";
}
std::cout << std::endl;
return 0;
}
3. move, rvalue reference, std::move
`move`와 rvalue reference는 C++11에서 도입된 중요한 개념으로, 객체의 소유권을 효율적으로 이전할 수 있게 해줍니다.
3.1. rvalue reference
rvalue reference는 객체의 임시 값을 다룰 때 유용합니다. 이를 통해 값의 복사를 피하고, 성능을 최적화할 수 있습니다.
#include <iostream>
void print(int&& a) { // rvalue reference
std::cout << a << std::endl;
}
int main() {
print(10); // rvalue 전달
return 0;
}
3.2. std::move
`std::move`는 객체를 rvalue로 변환하여 소유권을 다른 객체로 이전하는 데 사용됩니다.
#include <iostream>
#include <utility>
void print(int&& a) {
std::cout << a << std::endl;
}
int main() {
int x = 10;
print(std::move(x)); // x를 move하여 전달
std::cout << x << std::endl; // x는 더 이상 유효하지 않음
return 0;
}
4. constexpr, noexcept, std::optional
C++11부터 추가된 `constexpr`, `noexcept`, `std::optional`은 코드의 효율성을 높이고, 안정성을 강화하는 도구입니다.
4.1. constexpr
`constexpr`는 컴파일 타임에 값을 계산하도록 지시하는 키워드입니다. 이는 프로그램 성능을 향상시킬 수 있습니다.
#include <iostream>
constexpr int square(int x) { return x * x; }
int main() {
int result = square(5); // 컴파일 타임에 계산
std::cout << result << std::endl;
return 0;
}
4.2. noexcept
`noexcept`는 함수가 예외를 던지지 않음을 명시적으로 표시하는 키워드입니다. 이를 통해 컴파일러 최적화를 유도할 수 있습니다.
#include <iostream>
void print() noexcept { // 예외를 던지지 않는 함수
std::cout << "No exception!" << std::endl;
}
int main() {
print();
return 0;
}
4.3. std::optional
`std::optional`은 값이 있을 수도 있고 없을 수도 있는 경우를 표현하는 데 사용됩니다. 값이 없을 경우 `nullopt`를 사용합니다.
#include <iostream>
#include <optional>
std::optional<int> getValue(bool condition) {
if (condition) {
return 10;
}
return std::nullopt; // 값 없음
}
int main() {
auto value = getValue(true);
if (value) {
std::cout << *value << std::endl;
}
return 0;
}
5. 구조적 바인딩, 개념 (Concepts)
C++17에서 도입된 구조적 바인딩과 C++20에서 도입된 개념은 코드의 가독성과 안정성을 높여주는 중요한 기능입니다.
5.1. 구조적 바인딩
구조적 바인딩은 튜플과 같은 복합 자료형에서 각 값을 쉽게 추출할 수 있도록 해줍니다.
#include <iostream>
#include <tuple>
int main() {
std::tuple<int, double, std::string> t = {1, 3.14, "Hello"};
auto [a, b, c] = t; // 구조적 바인딩
std::cout << a << ", " << b << ", " << c << std::endl;
return 0;
}
5.2. 개념 (Concepts)
C++20에서 도입된 개념은 템플릿을 보다 쉽게 관리할 수 있게 해주며, 특정 조건을 만족하는 타입만을 허용하도록 합니다.
#include <iostream>
template <typename T>
concept Incrementable = requires(T t) {
{ t++ } -> std::same_as<T>;
};
template <Incrementable T>
T increment(T t) {
return t + 1;
}
int main() {
std::cout << increment(10) << std::endl;
return 0;
}