더북(TheBook)

스마트 포인터 원소로 문자열에 접근하는 것은 원시 포인터로 접근하는 것과 완벽하게 같다. 앞에서 원시 포인터로 words의 내용을 출력한 코드 조각에서 원시 포인터를 스마트 포인터로 바꿔도 잘 동작한다. 물론, 자유 공간에서 string 객체를 지울 필요도 없다. 이 부분은 스마트 포인터가 알아서 처리한다. words.clear()를 실행하면 모든 원소를 제거하고, 원소가 제거될 때 스마트 포인터의 소멸자도 호출될 것이다. 즉, 스마트 포인터가 가리키는 객체에 할당된 메모리도 해제된다.

vector 컨테이너가 메모리 추가 할당을 너무 하는 걸 예방하려면 vector를 생성하고 reserve()를 호출해서 초기 메모리를 할당해 두는 게 좋다.

std::vector<std::shared_ptr<std::string>> words;
words.reserve(100);                     // 스마트 포인터 100개를 위한 공간

원소 개수를 지정해서 vector를 생성하는 것보단 reserve()를 호출하는 방법이 더 좋다. 원소 개수를 지정해서 vector를 생성하면 각 원소가 생성될 때마다 shared_ptr<string> 생성자를 호출하게 된다. 이게 큰 문제는 아니지만, 작은 오버헤드라도 불필요한 오버헤드를 만들 필요는 없다. 대부분은 스마트 포인터가 가리키는 객체에 필요한 공간보다 스마트 포인터에 필요한 공간이 훨씬 더 적으니 reserve()로 공간을 할당하는 정도는 괜찮다.

shared_ptr<T> 객체로 저장하면 컨테이너 바깥에도 포인터의 복제본을 들 수 있다. 이렇게 할 필요가 없다면 unique_ptr<T> 객체를 사용해야 한다. 다음은 words 벡터에 유니크 포인터를 사용하는 코드다.

std::vector<std::unique_ptr<std::string>> words;
std::string word;
std::cout << "Enter words separated by spaces, enter Ctrl+Z on a separate line to end:\n";
while (true)
{
  if ((std::cin >> word).eof())
  {
    std::cin.clear();
    break;
  }
  words.push_back(std::make_unique<string>(word)); // string에 대한 스마트 포인터를 생성하고 저장
}

코드에서 sharedunique로 바꾼 것을 빼면 같은 코드다.

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.