IT story

weak_ptr은 어떻게 작동합니까?

hot-time 2020. 12. 25. 09:32
반응형

weak_ptr은 어떻게 작동합니까?


내가 사용하는 방법을 이해 weak_ptr하고 shared_ptr. 나는 shared_ptr그 객체의 참조 수를 세어 어떻게 작동 하는지 이해 합니다. 어떻게 weak_ptr작동합니까? 부스트 소스 코드를 읽어 보았지만 부스트가 사용하는 모든 것을 이해할만큼 충분히 익숙하지 않습니다.

감사.


shared_ptr참조 카운트를 저장하기 위해 추가 "카운터"개체 (일명 "공유 카운트"또는 "제어 블록")를 사용합니다. (BTW : 그 "카운터"객체는 또한 삭제자를 저장합니다.)

shared_ptr과는 weak_ptr실제 pointee에 대한 포인터 및 "카운터"개체에 두 번째 포인터를 포함합니다.

을 구현하기 weak_ptr위해 "counter"객체는 두 개의 다른 카운터를 저장합니다.

  • "사용 횟수"는 shared_ptr개체를 가리키는 인스턴스 의 수입니다 .
  • "약한 수"는 weak_ptr개체를 가리키는 인스턴스 수이며 "사용 횟수"가 여전히> 0 인 경우 1을 더합니다.

포인트는 "사용 횟수"가 0이되면 삭제됩니다.

"counter"도우미 개체는 "weak count"가 0에 도달하면 삭제됩니다 (즉, "use count"도 0이어야 함, 위 참조).

shared_ptr에서 를 얻으려고 할 때 weak_ptr라이브러리는 "사용 횟수"를 원자 적으로 확인하고 0보다 크면 증가합니다. 성공하면 shared_ptr. "사용 횟수"가 이미 0이면 shared_ptr대신 인스턴스 를 얻습니다 .


편집 : 이제 두 카운트가 모두 0으로 떨어질 때 "카운터"개체를 해제하는 대신 약한 카운트에 1을 추가하는 이유는 무엇입니까? 좋은 질문.

대안은 "사용 횟수"와 "약한 횟수"가 모두 0으로 떨어질 때 "카운터"개체를 삭제하는 것입니다. 첫 번째 이유는 다음과 같습니다. 모든 플랫폼에서 두 개의 (포인터 크기) 카운터를 원자 적으로 확인하는 것은 불가능하며, 그것이있는 경우에도 하나의 카운터 만 확인하는 것보다 더 복잡합니다.

또 다른 이유는 삭제자가 실행이 완료 될 때까지 유효해야한다는 것입니다. 삭제자는 "카운터"개체에 저장되므로 "카운터"개체가 유효해야합니다. shared_ptr하나의 weak_ptr객체 와 하나의 객체가 있고 동시 스레드에서 동시에 재설정되는 경우 어떤 일이 발생할 수 있는지 고려하십시오 . shared_ptr먼저 온다고 합시다 . "사용 횟수"를 0으로 줄이고 삭제 자 실행을 시작합니다. 이제 weak_ptr"weak count"가 0으로 감소하고 "use count"도 0이라는 것을 알게됩니다. 따라서 "카운터"개체와 함께 삭제 자도 함께 삭제됩니다. 삭제자가 여전히 실행 중입니다.

물론 "카운터"객체가 살아남는 것을 보장하는 다른 방법이있을 수 있지만 "약한 카운트"를 1 씩 늘리는 것이 매우 우아하고 직관적 인 해결책이라고 생각합니다. "약한 카운트"는 "카운터"개체에 대한 참조 카운트가됩니다. 그리고 shared_ptrs도 카운터 개체를 참조하므로 "약한 개수"도 증가시켜야합니다.

아마도 더 직관적 인 해결책은 shared_ptr모든 단일 shared_ptr보유가 "카운터"객체에 대한 참조 이기 때문에 모든 단일에 대해 "약한 수"를 증가시키는 것 입니다.

모든 shared_ptr인스턴스에 하나를 추가 하는 것은 단지 최적화 일뿐입니다 ( shared_ptr인스턴스를 복사 / 할당 할 때 하나의 원자 적 증가 / 감소를 절약 함 ).


기본적으로 "weak_ptr"은 코드 뒷부분에서 강력한 참조 (예 : "shared_ptr")를 복구 할 수있는 일반 "T *"포인터입니다.

일반 T *와 마찬가지로 weak_ptr은 참조 계산을 수행하지 않습니다. 내부적으로 임의의 유형 T에 대한 참조 계산을 지원하기 위해 STL (또는 이러한 종류의 논리를 구현하는 다른 라이브러리)은 "Anchor"라고하는 래퍼 개체를 만듭니다. "Anchor"는 참조 횟수를 구현하기 위해서만 존재하며 "count가 0이면 delete 호출"동작이 필요합니다.

강력한 참조에서 shared_ptr는 "Anchor"의 참조 수를 업데이트하기 위해 복사, operator =, 생성자, 소멸자 및 기타 관련 API를 구현합니다. 이것이 shared_ptr이 누군가가 그것을 사용하는 동안 당신의 "T"가 정확히 살아 있는지 확인하는 방법입니다. "weak_ptr"에서 동일한 API는 실제 Anchor ptr을 복사합니다. 참조 횟수를 업데이트하지 않습니다.

이것이 "weak_ptr"의 가장 중요한 API가 "만료"되고 이름이 잘못된 "잠금"인 이유입니다. "Expired"는 기본 개체가 여전히 주변에 있는지 여부를 알려줍니다. 즉 "모든 강력한 참조가 범위를 벗어 났기 때문에 이미 자체적으로 삭제 되었습니까?" "Lock"은 (가능하다면) weak_ptr을 강력한 참조 shared_ptr로 변환하여 참조 카운트를 복원합니다.

BTW, "잠금"은 해당 API에 대한 끔찍한 이름입니다. 당신은 (그냥) 뮤텍스를 호출하는 것이 아니라, "앵커"가 작동하는 약한 참조로부터 강한 참조를 만들고 있습니다. 두 템플릿의 가장 큰 결점은 operator->를 구현하지 않았다는 것입니다. 그래서 여러분의 객체로 무엇이든하기 위해서는 원시 "T *"를 복구해야합니다. 기본 유형은 "->"연산자를 지원하지 않기 때문에 주로 "shared_ptr"과 같은 것을 지원하기 위해이 작업을 수행했습니다.

참조 URL : https://stackoverflow.com/questions/5671241/how-does-weak-ptr-work

반응형