(똑똑한 포인터)
std::auto_ptr는 코드를 C++98 컴파일러로도 컴파일해야 하는 상황에서나 필요할 뿐입니다. 그런 제약이 없다면, 코드에서 모든 std::auto_ptr를 std::unique_ptr로 대체한 후 std::auto_ptr에 대해서는 완전히 잊는 것이 좋습니다.
똑똑한 포인터 API들은 놀랄 만큼 가지각색입니다. 네 가지 똑똑한 포인터에 공통인 기능성은 기본 생성(default construction)뿐입니다. 이 API들에 관한 상세한 참고자료를 구하는 것은 아주 쉬운 일이므로, 이번 장에서는 API의 개요에 종종 빠져 있는 정보, 이를테면 주목할 만한 용례나 실행 시점 비용 분석 등을 논의하는 데 집중하기로 합니다. 그런 정보에 정통하면 똑똑한 포인터를 그냥 사용하는 수준에서 벗어나서 효과적으로 사용하는 경지에 올라설 수 있을 것입니다.
Chapter(18) 소유권 독점 자원의 관리에는 std::unique_ptr를 사용할 것
똑똑한 포인터 중 하나를 고를 때 가장 먼저 고려해야 할 것은 std:unique_ptr입니다. 기본적으로 std::unique_ptr는 생 포인터와 같은 크기라고 가정하는 것이 비합리적인 일이 아니며, 대부분의 연산(역참조를 비롯해서)에서 std::unique_ptr는 생 포인터와 정확히 동일한 명령들을 실행합니다. 이는 메모리와 CPU 주기(cycle)가 넉넉하지 않은 상황에서도 std::unique_ptr를 사용할 수 있음을 뜻합니다. 생 포인터가 충분히 작고 충분히 빠른 상황이라면, std::unique_ptr 역시 그럴 것이 거의 확실합니다.
std::unique_ptr는 독점권 소유권(exclusive ownership) 의미론을 체현하고 있습니다. 널이 아닌 std::unique_ptr는 항상 자신이 가리키는 객체를 소유합니다. std::unique_ptr를 이동하면 소유권이 원본 포인터에서 대상 포인터로 옮겨집니다. (원본 포인터는 널로 설정됩니다.) std::unique_ptr의 복사는 허용되지 않는데, 만일 std::unique_ptr를 복사할 수 있다면, 두 std::unique_ptr가 같은 자원을 가리킬 뿐만 아니라 두 포인터 모두 자신이 그 자원을 소유하고 있다고(따라서 그 자원을 파괴해야 한다고) 생각하는 상화이 빚어질 것이기 때문입니다. 그런 의미에서, std::unique_ptr는 이동 전용 형식(move-only type)입니다. 널이 아닌 std::unique_ptr는 소멸 시 자신이 가리키는 자원을 파괴합니다. 기본적으로, 자원 파괴는 std::unique_ptr안에 있는 생 포인터에 delete를 적용함으로써 수행됩니다.
std::unique_ptr의 흔한 용도 하나는, 계통구조(hierarchy) 안의 객체를 생성하는 팩터리 함수의 반환 형식으로 쓰이는 것입니다. 주식(stock), 채권(bond), 부동산 (real estate) 같은 여러 종류의 투자 대상들을 대표하는, Investment를 기반 클래스로 삼은 다음과 같은 계통 구조가 있다고 합시다.
<의사 코드>
class Investment { ... } ;
class Stock:
public Investment { ... };
class Bond:
public Investment { ... };
class RealEstate:
public Investment { ... };
이런 계통구조에 대한 팩토리 함수는 흔히 힙에 객체를 생성하고 그 객체를 가리키는 포인터를 돌려줍니다. 그 객체가 더 이상 필요하지 않게 되었을 때 객체를 삭제하는 것은 호출자의 몫입니다. std::unique_ptr는 이런 용법에 완벽히 적합합니다. 팩터리가 돌려준 자원의 관리는 전적으로 호출자의 책임인데(다른 말로 하면, 호출자가 그 자원을 독점적으로 소유합니다), std::unique_ptr는 소멸 시 피지칭 객체를 자동으로 삭제해 주기 때문입니다. Investment 계통 구조를 위한 팩토리 함수의 선언이 다음과 같다고 합시다.
templage<typename... Ts> // 주어진 인수들로 생성한 객체를 가리키는 std::unique_ptr를 돌려줌
std::unique_ptr<Investment>
makeInvestment(Ts&&... params);
다음은 이 팩터리 함수가 반환한 std::unique_ptr를 하나의 범위 안에서 사용하는 예입니다.
{
...
auto pInvestment = // pInvestment의 형식은 std::unique_ptr<Investment>
makeInvestment( 인수들 );
...
} // *pInvestment가 파괴됩니다
그런데 std::unique_ptr를 소유권 이전 시나리오에서 사용할 수도 있습니다. 예를 들어 팩터리 함수가 돌려준 std::unique_ptr를 어떤 컨테이너 안으로 이동하고, 이후 그 컨테이너 요소를 어떤 객체의 한 자료 멤버로 이동하고, 그 후 어느 시점에서 그 객체가 파괴된다고 합시다. 이때 객체의 std::unique_ptr 자료 멤버 역시 파괴되며, 해당 소멸자에 의해 팩터리가 돌려준 자원이 파괴됩니다.
'컴퓨터과학' 카테고리의 다른 글
[Effective C++] (18-3) 소유권 독점 자원의 관리에는 std::unique_ptr를 사용할 것 (0) | 2020.06.17 |
---|---|
[Effective C++] (18-2) 소유권 독점 자원의 관리에는 std::unique_ptr를 사용할 것 (0) | 2020.06.15 |
[Effective C++] (17-4) 특수 멤버 함수들의 자동 작성 조건을 숙지할 것 / (똑똑한 포인터) (0) | 2020.06.13 |
[Effective C++] (17-3) 특수 멤버 함수들의 자동 작성 조건을 숙지할 것 (0) | 2020.06.11 |
[Effective C++] (17-2) 특수 멤버 함수들의 자동 작성 조건을 숙지할 것 (0) | 2020.06.10 |