학습
C++ C++의 메모리 관리 최적화
C++ C++의 메모리 관리 최적화 — 고급
C++의 메모리 관리 최적화
1. 도입 (왜 배워야 하는가)
C++는 성능이 중요한 응용 프로그램에서 흔히 사용되는 언어입니다. 그 이유는 C++가 메모리 관리에 대한 높은 유연성을 제공하기 때문입니다. 하지만 이 유연성은 동시에 책임을 동반합니다. 메모리 관리 최적화를 배우지 않으면 메모리 누수, 불필요한 메모리 사용, 프로그램의 비효율성이 발생할 수 있습니다. 이러한 문제는 프로그램의 성능을 저하시킬 뿐만 아니라 최악의 경우 애플리케이션 충돌이나 데이터 손실로 이어질 수 있습니다. 따라서 C++ 프로그래머는 메모리 관리의 원리를 이해하고 최적화 기법을 익혀야 합니다.
2. 핵심 개념 설명
동적 메모리 할당
- 정의: 프로그램 실행 중에 필요에 따라 메모리를 할당하고 해제하는 과정입니다.
- 비유: 식당에서 손님이 주문할 때마다 요리를 준비하는 것과 같습니다. 손님이 적을 때는 적게, 많을 때는 많이 요리하는 것이죠.
- 정의: C++11에서 도입된 객체로, 메모리를 자동으로 관리해주는 포인터입니다.
std::unique_ptr,std::shared_ptr,std::weak_ptr등이 있습니다. - 비유: 친구와 함께 차를 나누어 타는 것처럼, 누가 차를 운전할지를 정해두면 불필요한 혼잡을 피할 수 있습니다.
스마트 포인터
| 용어 | 설명 |
|---|---|
std::unique_ptr | 소유권을 단일 객체에만 부여합니다. |
std::shared_ptr | 여러 객체가 같은 메모리를 공유합니다. |
std::weak_ptr | shared_ptr와 함께 사용해 순환 참조를 방지합니다. |
3. 기본 코드 예제
동적 메모리 할당 예제
#include <iostream>
int main() {
int ptr = new int(5); // 동적으로 정수 5를 할당
std::cout << ptr << std::endl; // 5 출력
delete ptr; // 메모리 해제
return 0;
}
5
- int* ptr = new int(5);: 힙 메모리에 정수 5를 할당하고 그 주소를 ptr에 저장합니다.
- std::cout << *ptr << std::endl;: 포인터가 가리키는 값을 출력합니다.
- delete ptr;: 할당된 메모리를 해제하여 메모리 누수를 방지합니다.
스마트 포인터 예제
#include <iostream>
#include <memory> // 스마트 포인터를 사용하기 위한 헤더
int main() {
std::unique_ptr<int> ptr(new int(10)); // unique_ptr 사용
std::cout << *ptr << std::endl; // 10 출력
return 0; // ptr의 소멸자 호출로 메모리 자동 해제
}
10
- std::unique_ptr<int> ptr(new int(10));: unique_ptr을 사용하여 정수 10을 동적으로 할당합니다.
- std::cout << *ptr << std::endl;: 포인터가 가리키는 값을 출력합니다.
- return 0;: ptr이 소멸되면서 자동으로 메모리가 해제됩니다.
4. 실전 활용 예제
예제 1: 쇼핑몰 장바구니 구현
#include <iostream>
#include <vector>
#include <memory>
class Item {
public:
std::string name;
Item(std::string n) : name(n) {}
};
class Cart {
std::vector<std::shared_ptr<Item>> items; // 아이템을 저장할 벡터
public:
void addItem(std::shared_ptr<Item> item) {
items.push_back(item); // 아이템 추가
}
void showItems() {
for (const auto& item : items) {
std::cout << item->name << std::endl; // 아이템 이름 출력
}
}
};
int main() {
Cart cart;
cart.addItem(std::make_shared<Item>("사과"));
cart.addItem(std::make_shared<Item>("바나나"));
cart.showItems(); // 장바구니의 아이템 출력
return 0;
}
예제 2: 그래프 데이터 구조
#include <iostream>
#include <vector>
#include <memory>
class Node {
public:
int value;
std::vector<std::shared_ptr<Node>> neighbors; // 인접 노드
Node(int v) : value(v) {}
};
class Graph {
public:
std::vector<std::shared_ptr<Node>> nodes; // 그래프의 노드
void addNode(int value) {
nodes.push_back(std::make_shared<Node>(value)); // 노드 추가
}
};
int main() {
Graph graph;
graph.addNode(1);
graph.addNode(2);
std::cout << "그래프에 노드 추가 완료!" << std::endl;
return 0;
}
5. 흔한 실수와 주의사항
실수 1: 메모리 해제를 잊음
int* ptr = new int(5);
// delete ptr; // 메모리 해제를 잊음
실수 2: 스마트 포인터를 잘못 사용
std::shared_ptr<int> ptr1(new int(5));
std::shared_ptr<int> ptr2 = ptr1; // 순환 참조로 인한 메모리 누수