2014-04-22 3 views
7

std::weak_ptrstd::owner_less과 관련 컨테이너 std::setstd::map에 대한 사용과 관련하여 많은 질문이 오늘있었습니다. 약한 포인터가 만료되면 정의되지 않은 동작이므로 std::set에있는 weak_ptr을 사용하면 올바르지 않다고하는 많은 게시물이 있습니다. 이 올바른지?std :: map에서 weak_ptr을 사용하는 것이 안전합니까?

답변

9

이유 중 하나는 std::owner_less이 주문을 제공하고 약한 포인터 만료시 안전을 보장하는 것입니다. 내 로직

먼저 std::owner_less

  • 연산자의 정의() operator() 의해 정의 동치 관계하에 25.4

    항에 엄격한 약한 순서를 정의 !operator()(a, b) && !operator()(b, a)shared_ptr이고 또는 weak_ptr 인스턴스는 소유권을 공유하거나 둘 다 비어있는 경우에만 동등합니다.

두 경우 그들은 실제 용어는 동일한 참조 횟수 객체를 공유하는 것을 의미 같은 객체를 공유

  1. 이다.
  2. 둘 다 비어 있습니다.

이제 혼란이 두 번째 임기를 넘었다 고 생각합니다. 핵심은 표준에서 "비어 있음"은 weak_ptr이 모든 개체와 소유권을 공유하지 않는다는 것을 의미합니다. 또, 표준 상태

  • constexpr weak_ptr() noexcept;

    효과

    는 : 빈 weak_ptr 오브젝트를 구축합니다.
    사후 조건 : use_count() == 0.
  • template<class Y> weak_ptr(const shared_ptr<Y>& r) noexcept;

  • template<class Y> weak_ptr(const weak_ptr<Y>& r) noexcept;
  • weak_ptr(const weak_ptr& r) noexcept;
  • 이 필요합니다 Y*T*에 암시 적으로 변환하지 않는 한 두 번째와 세 번째 생성자는 오버로드 확인에 참여하지 않는다.

    효과 : r이 비어있는 경우 빈 weak_ptr 개체를 구성합니다. 그렇지 않은 경우 소유권을 공유하는 weak_ptr 개체를 r으로 구성하고 r에 저장된 포인터 복사본을 저장합니다.

    사후 조건 : use_count() == r.use_count().

스왑 두 weak_ptr (S)의 교환 상태를 정의하고, 할당 스왑 함께 상기 생성자를 사용하여 정의된다.

여기에서 중요한 점은 비어있는 weak_ptr을 생성하는 유일한 방법은 기본 구성이거나 이전에 비어있는 weak_ptr 또는 shared_ptr에서 복사/이동/할당하는 것입니다. 또한 weak_ptr 만료로 빈 weak_ptr을받을 수 없다는 점에 유의해야합니다. 만료 된 weak_ptr은 단순히 use_count이 0입니다. 실질적인 문제하는 shared_ptr 만들 때 std::make_shared가 사용될 때, 기준 카운트 객체가 shared_ptr 생성자를 사용하여 데이터로부터 분리하거나 동일한 메모리 할당에서 역시 생성 될 것처럼

. weak_ptrshared_ptr으로 구성되면 동일한 제어 구조 및 참조 횟수를 가리 킵니다. shared_ptr이 파괴되면 데이터가 파괴 될 수 있지만 소유권을 공유하는 weak_ptr이 모두 제거 될 때까지 참조 횟수 객체가 유지되어야합니다. 그렇지 않으면 weak_ptr에 매달린 포인터 참조가 있습니다.

그래서, 함께이 모든 그것만큼 당신이 순서를 수행 할 std::owner_less을 사용하는 등의 std::map의 그들이 키로 또는 std::setstd::weak_ptr을 사용하는 것이 안전하다는 것을 의미한다. 위의 내용에 따라 weak_ptr의 주문은 컨테이너에있는 동안 만료 되더라도 그대로 유지됩니다.

+0

이 답변에 결론을 추가 할 수 있습니까? :) – Drax

+0

@Drax : 물론. 나는 밤늦게이 편지를 썼다. 나는 그런 작은 정보를 놓쳤다. –

+0

멋진, 고마워요. :) – Drax