C++에는 아주 유용한 개념이 있다
메모리 관리를 할 때마다 고려해야할 점은 바로 "메모리 누수"인데,
그것에 대해 조금은 자유롭게 생각할 수 있는 스마트 포인터라는 것이다
가장 자주 사용하는건 shared_ptr이었는데,
여러 개가 있는건 이유가 있다는 생각이 들어서
하나씩 정리하려고 한다
(모던 C++ 입문 교재를 참고해서 작성하였습니닥)
1. 스마트 포인터에는 뭐가 있지?
스마트 포인터는 3가지가 있다
1) unique_ptr (오늘할거)
2) shared_ptr
3) weak_ptr
요렇게 3가지 인데, 참고로 스마트 포인터는 C++ 11에서 도입된 개념이다
C++ 03에는 auto_ptr라는 것도 있다고 한다 -_-a 하지만 삭제됨 쓰지마셈
1-1) 스마트 포인터 헤더는?
#include <memory>
or
#include "boost/shared_ptr.hpp"
기본 STL에서 제공하는 스마트 포인터는 <memory> 헤더에서 쓸 수 있다
근데 C++11에서 제공하는 기능인데, C++ 11을 사용할 수 없을 수도 있다...
그럴 때는 Boost에 있는걸 사용하면 된다고 한다
1-2) 그냥 포인터를 쓰면 안되는건가?
써도 된다 ㅋ
스마트 포인터를 사용시에 큰 장점은 사용하는 포인터가 만료되면
메모리가 자동으로 해제되기 때문에 메모리 관리 차원에서 편하다
하지만 구현하는데는 조금 까다롭고 유지보수가 어려울 수 있으니까
잘 알고 사용하자 ㅋ
2. unique_ptr
이름에서 느껴지는가... 뭔가 유니크하다
유니크할 것 같은 느낌이 든다..
unique_ptr은 포인터를 통해 Unique한 소유권을 가지고
unique_ptr 범위를 벗어날 때 해당 개체를 처리하는 스마트 포인터이다
바로 사용 예시를 보겠다
#include <memory>
#include <iostream>
using namespace std;
int main(void)
{
std::unique_ptr <int> ptr(new int(10));
cout << *ptr << endl;
return 0;
}
메모리에 대한 포인터에 대해서는 new로 생성 해줬고,
포인터이기 때문에 *ptr로 값을 출력을 해준 예제이다
해당 포인터는 만료되면 메모리가 자동으로 해제될 것이다
메모리는 자동으로 해제되지만, 메모리를 동적으로 할당해주지 않았다면
core가 발생하거나 오류가 발생할 수 있다
2-1) unique_ptr이 unique한 이유
unique_ptr은 유니크!!! 고유한!!! 포인터라는 이름을 갖고 있는 이유가 있다..
왜냐면, 다른 포인터 타입에 할당되거나 변경할 수 없다
데이터를 다른 값으로 바꾼다고 한다거나,
다른 unique_ptr 변수에 할당하려고 한다!? 하면
아래와 같은 에러가 뜰 것이다
"error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]"
포인터가 가르키는 데이터를 얻고 싶다면 get()이라는 함수를 사용하면 된다
바로 요렇겜
#include <memory>
#include <iostream>
using namespace std;
int main(void)
{
std::unique_ptr <int> ptr(new int(10));
cout << *ptr << endl;
int* raw_ptr = ptr.get();
cout << *ptr << endl;
return 0;
}
unique_ptr은 다른 unique_ptr에 할당하는 것도 안된다
int main(void)
{
std::unique_ptr <int> ptr(new int(10));
cout << *ptr << endl;
/* 에러 발생 */
std::unique_ptr <int> ptr_cp{ptr};
cout << *ptr_cp << endl;
return 0;
}
위에서 언급한 같은 에러가 날 것이다 ㅋ
unique_ptr은 이동만 할 수 있다
이동은 무슨 함수냐... move() 다
std::unique_ptr <int> ptr_cp{move(ptr)};
바로 이렇게 ㅋ
move() 불필요한 복사를 피하려고 트릭을 사용하는 문법인데
그림을 빌려 설명하자면
ptrA에 Song 객체의 소유권이 부여되고,
move를 하면 그 소유권을 그대로 ptrB에 넘겨주게 된다
ptrA는 nullptr이 된다ㅋ
정리하자면 unique_ptr은 데이터를 복제하는 복사(copy)는 안돼요
원래 주소에서 데이터를 전송하는 이동(move)은 돼요
→ 고유한 소유권이 있기 때문이다
2-2) unique_ptr을 생성하는 방법은 new뿐인가?
아니다ㅋ
물론 이렇게도 많이 쓰는데, C++ 14 부터 제공하는 make_unique()를 쓰면
더 안전하고 코드에 통일성을 줄 수 있다
int main(void)
{
std::unique_ptr <int> ptr = make_unique<int>(10);
cout << *ptr << endl;
return 0;
}
바로 이렇게ㅋ
new로 사용하는게 습관이 되었는데, make 함수를 사용하도록 해야겠당
2-3) unique_ptr을 return 받으면 소유권은?
크게 생각안해도 된다
예시로 바로 긔긔
std::unique_ptr<int>
unique_func()
{
return std::unique_ptr<int>{new int(10.0)};
}
int main(void)
{
auto ptr = unique_func();
cout << *ptr << endl;
return 0;
}
요렇게 되면 unique_ptr을 함수에서 반환할 때
메모리의 소유권을 전달하기 때문에, 이 경우에는 move를 하지 않아도 된다
2-4) 메모리 영역을 지우고 싶다면?
스마트 포인터를 사용하지 않을 경우에는
알아서 delete가 된다고 알고 있지만... 메모리 영역을 내가 지우고 싶을 수도 있지 않은감
그럴때는 reset()이라는 함수를 사용하면 된다
int main(void)
{
std::unique_ptr <int> ptr(new int(10));
cout << *ptr << endl;
std::unique_ptr <int> ptr_cp{move(ptr)};
cout << *ptr_cp << endl;
ptr_cp.reset();
if( !ptr_cp )
cout << "nullptr" << endl;
else
cout << *ptr_cp << endl;
return 0;
}
요렇게 하면 nullptr이라는 문자열이 출력된다
ptr_cp에는 ptr의 메모리 영역을 move하여 갖고 있는데,
ptr_cp에 대해서 reset()을 하여 메모리 영역을 삭제했기 때문이다
내일은 shared_ptr 공부할래
'BackEnd > C랑 C++' 카테고리의 다른 글
Error 해결: undefined reference to `vtable for XXX' (0) | 2021.06.24 |
---|---|
Boost-echo tcp client & server를 살펴보자 (1) (2) | 2021.06.11 |
Boost Asio에 대해서 알아보자 (6) | 2021.05.20 |
C++ 클래스 멤버변수 초기화를 알아보자 (4) | 2021.03.25 |
C++ 대문자/소문자 변환 (4) | 2021.02.26 |