description
unique_ptr은 이름에서 알 수 있듯이 하나의 대상에 하나의 unique_ptr 포인터로만 가리킬 수 있습니다.
auto_ptr과 비슷해 보이지만 auto_ptr과 다르게 컴파일 에러를 발생시켜 하나의 대상에 여러 개의 포인터가 가리키는 일을 컴파일 단계에서 차단해 줍니다.
사용 방법은 아래와 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<iostream>
#include<memory>
using namespace std;
class TEST
{
public:
TEST()
{
cout << "생성자 호출" << endl;
}
~TEST()
{
cout << "소멸자 호출" << endl;
}
void Print()
{
cout << "Print" << endl;
}
};
int main()
{
unique_ptr<TEST> up(new TEST());
}
// 출력 결과
생성자 호출
소멸자 호출
위에서 설명했듯이, 하나의 대상에 하나의 unique_ptr 포인터로만 가리킬 수 있기 때문에
다른 unique_ptr 포인터로 가리키게 된다면 컴파일 에러가 발생하는 것을 볼 수 있습니다.
1
2
3
4
5
6
7
int main()
{
unique_ptr<TEST> up(new TEST());
unique_ptr<TEST> up2(up); // Compile Error!!!!
unique_ptr<TEST> up3;
up3 = up; // Compile Error!!!!
}
컴파일 에러가 발생하는 이유는
unique_ptr 정의부를 가보면 “복사 생성자”와 “대입 연산자”에 대해 delete 처리를 했기 때문입니다.( == 삭제된 함수)
소유권 이전하기
만약 소유권을 이전해야 한다면 어떻게 해야 할까요??
unique_ptr은 “복사 생성자”와 “대입 연산자”가 delete 처리되어 삭제된 함수로 취급하고 있습니다.
그렇기 때문에 복사 생성자와 대입 연산자로 소유권을 이전할 수 없는데요.
대신 “이동 생성자”와 “이동 대입 연산자”를 지원하고 있습니다.
그렇기 때문에 std::move를 통해 소유권을 이전할 수 있습니다.
여담으로
“이동 생성자”와 “이동 대입 연산자”로 소유권을 이전하는 것은
unique_ptr이 소유권을 이전할 때 왜 원본 데이터가 NULL이 되는지에 대한 증명으로도 볼 수 있습니다.
“이동 생성자”를 통해 객체를 생성하면
원본 객체의 자원을 얕은 복사로 가져오면서 원본 객체는 NULL 처리하기 때문입니다.
std::move는 특정 객체가 이동될 수 있음을 알려주는 함수입니다.
여기서 “이동”이란, 특정 객체가 가지고 있는 자원을 효율적으로 전달할 수 있음을 뜻합니다.정리하면, std::move는 자원을 다른 객체로 효율적으로 전달할 수 있음을 알려주는 함수입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<iostream>
#include<memory>
using namespace std;
class TEST
{
int num = 0;
public:
TEST(int p_num):num(p_num)
{
cout << "생성자 호출" << endl;
}
~TEST()
{
cout << "소멸자 호출" << endl;
}
void Print()
{
cout << num << endl;
}
};
int main()
{
unique_ptr<TEST> up(new TEST(10));
unique_ptr<TEST> up2;
up2 = move(up);
up2->Print();
if (!up)
cout << "up is null" << endl;
}
// 출력 결과
생성자 호출
10
up is null
소멸자 호출
소유권 이전된 unique_ptr 포인터는 댕글링 포인터가 됩니다.
그러므로 댕글링 포인터가 된 unique_ptr 포인터를 가지고 값을 참조하려고 하면 런타임 에러가 발생하니 주의해야 합니다.