C ++에서 비어있는 std :: shared_ptr의 차이점은 무엇입니까?


80

cplusplus.com의 shared_ptr페이지는 구별 부른다 std::shared_ptr널을 shared_ptr . cppreference.com 페이지 를 명시 적으로 모두 "빈"와 비교 차이를 불러하지만, 사용하지 않는 nullptr자사의 설명에 std::shared_ptr행동.

비어있는 것과 널 사이에 차이점이 shared_ptr있습니까? 이러한 혼합 동작 포인터에 대한 사용 사례가 있습니까? 비어 있지 않은 null shared_ptr도 의미가 있습니까? 정상적인 사용에서 (즉, 명시 적으로 구성하지 않은 경우) 비어 있지만 null이 아닌 경우가 발생할 수 shared_ptr있습니까?

C ++ 11 버전 대신 Boost 버전을 사용하는 경우 이러한 답변이 변경됩니까?

답변:


80

이상한 shared_ptr행동 구석입니다 . 그것은 당신이 할 수있는 생성자가 shared_ptr소유 뭔가 를 가리키는 다른 뭔가를 :

template< class Y > 
shared_ptr( const shared_ptr<Y>& r, T *ptr );

shared_ptr이 생성자 사용하여 구성 주식 소유권 과를 r하지만, 포인트 어떤 ptr포인트 (즉, 호출 get()또는 operator->()반환합니다 ptr). 이것은 ptr소유 한 객체의 하위 객체 (예 : 데이터 멤버)를 가리키는 경우에 편리합니다 r.

페이지 당신은 전화 연결 shared_ptr아무것도 소유하지 않습니다 빈을 하고, shared_ptr그 아무것도 포인트 (즉, 누구의 get() == nullptr) 널 (null) . ( 이 의미에서 표준에 의해 Empty 가 사용됩니다. null 은 아닙니다.) null-but-not-empty shared_ptr를 생성 할 수는 있지만 그다지 유용하지는 않습니다. 빈-만 아니라 널은 shared_ptr본질적으로 같은 몇 가지 이상한 일을하는 데 사용할 수있는 비 소유 포인터이며, A는 기대 함수에 스택에 할당 무언가에 대한 포인터를 전달하는shared_ptr (하지만 넣어 누구든지 펀칭 좋을 것 shared_ptr내부를 먼저 API).

boost::shared_ptr또한 이 생성자가 그들이 전화 앨리어싱 생성자를 .


8
주목할만한 사항 : C ++ 11 § 20.7.2.2.1 (p16) "참고 :이 생성자는 shared_ptrNULL이 아닌 저장된 포인터 로 빈 인스턴스를 생성 할 수 있습니다 ." 또한 앞의 참고 (p15), "포인터가 매달릴 가능성을 피하기 위해이 생성자의 사용자 p는 소유권 그룹 r이 소멸 될 때까지 유효한 상태 를 유지 해야합니다."라고 언급 할 가치가 있습니다 . 실제로 거의 사용되지 않는 구조.
WhozCraig

@Cubbi A shared_ptrget()수익 nullptr nullptr 소유 여부 에 관계없이 동일합니다 .
TC

3
null이지만 비어 있지 않은 shared_ptrs 모든 소유 포인터가 범위를 벗어난 경우 일부 함수가 실행되도록하는 데 유용 할 수 있습니다 (예외의 경우에도!). 이것에 대한 특별한 수업이 있는지 확실하지 않습니다.
Coldfix

@coldfix null-but-nonempty shared_ptr는 non-null-and-nonempty가 shared_ptr할 수없는 것을 무엇으로 할 수 있습니까?
TC

2
앨리어싱 생성자는 Bloomberg에서 비롯되었으며 Boost에서 구현되기 전에 표준 용으로 제안되었습니다 ( N1851 참조 ). 나는 "함께 공유 소유권 표준의 용어를 선호 r말씨로"무엇이든 소유 " r소유"
조나단 Wakely

9

비어있는 것과 null shared_ptr 사이에 차이점이 있습니까?

Empty shared_ptr에는 제어 블록이 없으며 사용 횟수는 0으로 간주됩니다 . empty의 복사본 shared_ptr은 또 다른 비어 shared_ptr있습니다. 둘 다 shared_ptr공통 제어 블록이 없기 때문에 공유하지 않는 별도 의 s입니다. Empty shared_ptr는 기본 생성자 또는 nullptr.

비어 있지 않은 null shared_ptr에는 다른 shared_ptrs 와 공유 할 수있는 제어 블록이 있습니다 . 비어 있지 않은 널 (null)의 복사 shared_ptr입니다 shared_ptr원본과 동일한 제어 블록이 주 shared_ptr때문에 사용 횟수가 0이되지 않습니다 그것은 그 모든 사본라고 할 수 shared_ptr주 같은nullptr . 비어 있지 않은 null shared_ptr은 객체 유형의 null 포인터 (아님 nullptr) 로 생성 할 수 있습니다.

예를 들면 다음과 같습니다.

#include <iostream>
#include <memory>

int main()
{
    std::cout << "std::shared_ptr<int> ptr1:" << std::endl;
    {
        std::shared_ptr<int> ptr1;
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    std::cout << "std::shared_ptr<int> ptr1(nullptr):" << std::endl;
    {
        std::shared_ptr<int> ptr1(nullptr);
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    std::cout << "std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))" << std::endl;
    {
        std::shared_ptr<int> ptr1(static_cast<int*>(nullptr));
        std::cout << "\tuse count before copying ptr: " << ptr1.use_count() << std::endl;
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "\tuse count  after copying ptr: " << ptr1.use_count() << std::endl;        
        std::cout << "\tptr1 is " << (ptr1 ? "not null" : "null") << std::endl;
    }
    std::cout << std::endl;

    return 0;
}

다음을 출력합니다.

std::shared_ptr<int> ptr1:
    use count before copying ptr: 0
    use count  after copying ptr: 0
    ptr1 is null

std::shared_ptr<int> ptr1(nullptr):
    use count before copying ptr: 0
    use count  after copying ptr: 0
    ptr1 is null

std::shared_ptr<int> ptr1(static_cast<int*>(nullptr))
    use count before copying ptr: 1
    use count  after copying ptr: 2
    ptr1 is null

http://coliru.stacked-crooked.com/a/54f59730905ed2ff


1
나는 이것이 우리가 shared_ptr의 custom deleter에서 null을 확인 해야하는 이유에 대해 더 나은 대답이라고 생각합니다. shared_ptr의 사용자 정의 삭제 자에서 nullptr을 확인하는 것이 합리적입니까?
데이비드 리
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.