C++ 초급 - 12. 최신 C++ 기능 소개 (2 - C++14: 개선된 스마트 포인터)
2025. 2. 22. 18:07ㆍ프로그래밍 언어/C++
📌 12.2 C++14: 개선된 스마트 포인터
C++14에서는 C++11의 부족한 기능을 보완하고, 기존 문법을 개선하여 더 안전하고 직관적인 코드 작성이 가능하다.
그중 가장 중요한 개선점 중 하나는 스마트 포인터(std::unique_ptr)의 생성 방식 개선이다.
📌 1. std::make_unique를 활용한 안전한 스마트 포인터 생성
🔹 (1) 기존 std::unique_ptr 생성 방식 (C++11)
C++11에서는 std::unique_ptr을 생성할 때 new를 직접 사용해야 했다.
💡 예제: C++11에서 std::unique_ptr 생성
#include <iostream>
#include <memory> // 스마트 포인터 헤더 포함
int main() {
std::unique_ptr<int> ptr(new int(42)); // 직접 new 사용
std::cout << "값: " << *ptr << std::endl; // 42
return 0;
}
🔹 문제점
- 직접 new를 사용하면 예외 발생 시 메모리 누수가 발생할 가능성이 있음.
- 객체 생성과 스마트 포인터 초기화가 분리되어 있어, 코드가 불필요하게 복잡해짐.
🔹 (2) C++14의 std::make_unique
- C++14에서는 std::make_unique를 도입하여 std::unique_ptr을 더 안전하게 생성.
- 예외 안전성 (Exception Safety)을 보장하여, 객체가 안전하게 생성되도록 보장.
💡 예제: C++14에서 std::make_unique 사용
#include <iostream>
#include <memory> // 스마트 포인터 헤더 포함
int main() {
auto ptr = std::make_unique<int>(42); // 안전한 스마트 포인터 생성
std::cout << "값: " << *ptr << std::endl; // 42
return 0;
}
🔹 출력 결과
값: 42
🔹 장점
- new 키워드를 사용하지 않아 코드가 간결해짐.
- 예외가 발생해도 메모리 누수가 없음 (예외 안전성 보장).
- 스마트 포인터와 객체 생성이 한 번에 이루어져, 가독성이 좋아짐.
🔹 (3) std::make_unique로 배열 할당하기
- std::make_unique는 배열(std::unique_ptr<T[]>)도 안전하게 생성할 수 있음.
💡 예제: std::make_unique로 배열 생성
#include <iostream>
#include <memory>
int main() {
auto arr = std::make_unique<int[]>(5); // 크기 5의 정수 배열 생성
for (int i = 0; i < 5; i++) {
arr[i] = i * 10; // 배열 초기화
std::cout << arr[i] << " ";
}
std::cout << std::endl;
return 0;
}
🔹 출력 결과
0 10 20 30 40
💡 설명
- C++11에서는 배열을 std::unique_ptr<int[]>로 직접 할당해야 했지만, std::make_unique<int[]>(size)로 간단히 생성 가능.
- 메모리는 자동으로 해제되므로 delete[]가 필요 없음.
📌 2. C++11에서 부족했던 기능 보완 (기본적인 문법 개선)
🔹 (1) std::make_unique 도입의 배경
C++11에서는 std::make_shared가 존재했지만, std::make_unique가 없어서 std::unique_ptr을 사용할 때 new를 직접 사용해야 했다.
C++14에서는 이를 개선하여 std::make_unique를 제공함으로써, 예외 안전성을 높이고, 코드의 일관성을 유지할 수 있도록 했다.
🔹 (2) 기존 std::shared_ptr와의 비교
스마트 포인터 | C++11 방식 | C++14 방식 |
std::unique_ptr | std::unique_ptr<int> p(new int(10)); | auto p = std::make_unique<int>(10); |
std::shared_ptr | auto p = std::make_shared<int>(10); | auto p = std::make_shared<int>(10); (변경 없음) |
💡 차이점
- C++14에서는 std::make_unique가 추가되어 std::make_shared와 일관성이 생김.
- 더 이상 new를 직접 사용할 필요가 없음.
🔹 (3) std::make_shared와 std::make_unique의 차이점
특징 | std::make_unique() | std::make_shared() |
포인터 타입 | std::unique_ptr<T> | std::shared_ptr<T> |
객체 공유 | 불가능 (단일 소유권) | 가능 (참조 카운트 관리) |
메모리 관리 | 객체 단독 소유 | 여러 포인터가 공유 |
할당 방식 | std::unique_ptr 내부에서 new 호출 | 객체와 참조 카운트 메모리를 한 번에 할당 |
메모리 오버헤드 | 없음 | 참조 카운트용 추가 메모리 사용 |
사용 예시 | auto p = std::make_unique<int>(10); | auto p = std::make_shared<int>(10); |
💡 사용 기준
- 객체를 하나의 포인터에서만 관리해야 한다면 std::make_unique 사용.
- 객체를 여러 개의 포인터에서 공유해야 한다면 std::make_shared 사용.
🔹 (4) 스마트 포인터를 함수의 반환값으로 활용
- C++14부터 std::make_unique를 활용하면 스마트 포인터를 함수에서 안전하게 반환할 수 있음.
💡 예제: std::make_unique를 반환하는 함수
#include <iostream>
#include <memory>
std::unique_ptr<int> createUniquePtr() {
return std::make_unique<int>(100); // 안전한 스마트 포인터 반환
}
int main() {
auto ptr = createUniquePtr();
std::cout << "반환된 값: " << *ptr << std::endl; // 100
return 0;
}
🔹 출력 결과
반환된 값: 100
💡 설명
- 함수에서 std::make_unique로 생성한 스마트 포인터를 안전하게 반환 가능.
- C++11에서는 std::move()를 사용해야 했으나, C++14에서는 불필요.
📌 3. 정리
개념 | 설명 |
C++11 문제점 | std::unique_ptr를 생성할 때 new를 직접 사용해야 함 |
C++14 개선점 | std::make_unique 도입으로 더 안전한 std::unique_ptr 생성 가능 |
예외 안전성 | std::make_unique는 예외 발생 시 메모리 누수를 방지 |
배열 지원 | std::make_unique<T[]>(size)로 동적 배열 생성 가능 |
코드 일관성 | std::make_shared와 일관성을 유지하여 가독성 향상 |
'프로그래밍 언어 > C++' 카테고리의 다른 글
C++ 초급 - 12. 최신 C++ 기능 소개 (4 - C++20: concepts와 범위 기반 for 개선) (0) | 2025.02.22 |
---|---|
C++ 초급 - 12. 최신 C++ 기능 소개 (3 - C++17: 구조적 바인딩과 if constexpr) (0) | 2025.02.22 |
C++ 초급 - 12. 최신 C++ 기능 소개 (1 - C++11: 주요 기능 소개) (0) | 2025.02.22 |
C++ 초급 - 11. 표준 라이브러리(STL) (5 - std::algorithm (정렬 및 탐색 알고리즘)) (0) | 2025.02.22 |
C++ 초급 - 11. 표준 라이브러리(STL) (4 - std::pair, std::tuple (C++11 이후 다중 값 저장 컨테이너)) (0) | 2025.02.22 |