1. 개념
1. 스마트 포인터
자원 관리는 C++에서 가장 골치 아픈 문제입니다. 객체를 동적 할당받은 경우 "delete" 호출 없이 자원 해제가 되지 않기 때문에 "delete" 호출을 잊어버리는 경우 심각한 문제(eg 메모리 릭)가 발생할 수 있습니다. 더불어, 단순한 포인터의 동적 할당 수행은 Aliasing 문제도 동반합니다. 어떤 경우에는 하나의 포인터를 여러 코드 위치에서 복제하여 참조할 수 있습니다. 이때, 마지막으로 사용된 곳에서 "delete" 호출을 통해 자원 해제를 진행해야 하지만, 파악하기 굉장히 어렵죠.
이때, 스마트 포인터가 큰 도움을 줄 수 있습니다. 스마트 포인터는 "스택(정적 할당 받은 메모리들의 영역)"의 안정성과 유연성을 포함합니다. 스마트 포인터를 통해 동적 할당받은 메모리 영역은 지정 스코프를 벗어나면 자동으로 자원이 해제됩니다! 더불어, 일반 포인터와 같이 스마트 포인터는 참조 혹은 역참조 역시 가능합니다.
2. auto_ptr
1. 사용 금지!!!!
C++ 11 표준 이전에 제공되던 "auto_ptr"은 심각한 단점을 안고 있습니다. "auto_ptr"은 vector와 같은 STL 컨테이너에서는 정상적을 작동되지 않습니다! 따라서, "auto_ptr"는 사용하지 맙시다!
3. unique_ptr
1. 개념
unique_ptr는 C++에서 제공하는 스마트 포인터 중 하나로 단일 소유권 개념의 포인터 클래스입니다. 즉, unique_ptr는 한 번에 하나의 변수만 가리키는 포인터로 '복사' 작업이 불가능하고, '이동' 작업만 허용합니다.
2. 특징
- 단일 소유권
- 자동 메모리 해제
- 빠른 속도
3. 헤더 파일
#include <memory>
3. 코드
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include<memory>
using namespace std;
class SomeClass
{
public:
SomeClass(int a, int b)
: val1(a), val2(b)
{}
~SomeClass() = default;
int getVal1() { return val1; }
int getVal2() { return val2; }
private:
int val1;
int val2;
};
void PrintFunc()
{
// auto 사용도 가능!
unique_ptr<SomeClass> ptr = make_unique<SomeClass>(3, 5);
int val1 = ptr->getVal1();
int val2 = ptr->getVal2();
cout << val1 << " " << val2 << endl;
}
int main()
{
PrintFunc();
}
위 코드 예제에서 "SomeFunc()" 함수는 구현부에서 "SomeClass"의 객체를 동적 할당받습니다. 이때, "unique_ptr"를 통해 동적 할당받은 "SomeClass"객체는 함수의 종료와 함께 자동으로 해당 자원을 해제합니다.
추가적으로, (->)를 통해 역참조 또한 가능한것을 볼 수 있습니다!
#4. shared_ptr
1. 개념
shared_ptr는 C++에서 제공하는 스마트 포인터 중 하나로 '참조 카운팅' 방식의 포인터 클래스입니다. 즉, shared_ptr는 참조한 변수를 카운팅 하고, 참조한 변수가 0이 되면 자동으로 삭제되는 특징을 갖고 있습니다.
2. 특징
- 레퍼런스 카운팅
- 공동 소유권
- 자동 메모리 해제
- 스레드 안전
- 커스텀 삭제자
3. 헤더 파일
#include <memory>
4. 코드
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include<memory>
using namespace std;
class SomeClass
{
public:
SomeClass(int a, int b)
: val1(a), val2(b)
{}
~SomeClass() = default;
int getVal1() { return val1; }
int getVal2() { return val2; }
private:
int val1;
int val2;
};
int main()
{
shared_ptr<SomeClass> ptr = make_shared<SomeClass>(3, 5);
int val1 = ptr->getVal1();
int val2 = ptr->getVal2();
cout << val1 << " " << val2 << endl;
}
"shared_ptr"도 "unique_ptr"과 별반 다르지 않습니다. 포인터 초기화를위해 "make_shared"를 사용하는 것과, 동적으로 할당받은 C 스타일 배열을 담을 수 없다는 점만 "unique_ptr"와 다릅니다. "shared_ptr"의 제일 중요한 특징은 레퍼런스 카운팅입니다!
#5. 레퍼런스 카운팅
1. 개념
레퍼런스 카운팅은 어떤 클래스의 인스턴스 개수, 혹은 특정 객체의 사용처를 기억하기 위한 테크닉입니다. "shared_ptr"의 레퍼런스 카운팅의 경우 특정 포인터 혹은 객체에 대해 몇 개의 스마트 포인터가 생성되었는지 트래킹 합니다. 이 트래킹 정보를 통해 "중복 삭제"를 방지 할 수 있습니다. 아래 예제를 살펴보겠습니다.
2. 코드
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include<memory>
using namespace std;
class Nothing
{
public:
Nothing() { cout << "생성자 호출" << endl; }
virtual ~Nothing() { cout << "소멸자 호출" << endl; }
};
void DoubleDelete()
{
shared_ptr<Nothing> nothingPtr1 = make_shared<Nothing>();
shared_ptr<Nothing> nothingPtr2(nothingPtr1);
}
int main()
{
DoubleDelete();
}
위 예제 코드를 살펴보면, "DoubleDelete()" 함수 내부에서 동적 할당받은 "Nothing" 클래스 객체를 가리키는 스마트 포인터를 2개 선언했습니다. 스코프를 벗어나 해제되는 스마트 포인터가 2개임에도 불구하고, "소멸자는 한 번
만 호출됩니다!"
#6. 스마트 포인터와 이동 시맨틱
[Basic C++] #24_우측 값 참조, 대입 연산의 좌항과 우항
[Basic C++] #24_우측 값 참조, 대입 연산의 좌항과 우항 C++ 개발에서 까다로운 문법 혹은 특별한 의미를 갖는 부분에 대해 알아보겠습니다. "전문가를 위한 C"의 10 항목, "C++의 까다롭고 유별난 부분
webddevys.tistory.com
1. 스마트 포인터의 이동 시맨틱
shared_ptr<Nothing> func()
{
auto ptr = make_shared<Nothing>();
return ptr;
}
int main()
{
shared_ptr<Nothing> myPtr = func();
}
이동 시맨틱을 복기해보자면, 대입 원본 객체가 임시 객체여서 대입 대상으로의 복제 또는 대입이 끝난 후에 원본 객체의 멤버를 null 값으로 초기화시킵니다."얕은 복제"를 수행하죠! "func()" 함수는 보시다시피 "shared_ptr"를 반환합니다. 이때, C++는 자동으로 "std::move()"를 적용하여 shared_ptr의 이동 시맨틱이 동작되기 때문에 효율적입니다! unique_ptr 또한 동일하게 적용됩니다. unique_ptr의 경우 "이동 대입 연산"은 지원하는 대신에 일반 대입 연산자 혹은 복제 생성자를 지원하지 않습니다!
'언어 > Basic C++' 카테고리의 다른 글
[Basic C++] #28_static 키워드 (0) | 2022.10.09 |
---|---|
[Basic C++] #61_객체 풀, Obejct Pooling (0) | 2022.10.07 |
[Basic C++] #59_가비지 컬렉션 (1) | 2022.09.27 |
[Basic C++] #58_포인터, 배열과 포인터, 포인터 연산, 함수 포인터, 클래스 메서드 포인터 (0) | 2022.09.22 |
[Basic C++] #57_동적 메모리 (1) | 2022.09.20 |