2017-11-19 2 views
1

아래의 코드가 작동하지 않는 이유는 무엇입니까?shared_ptr에서 raw ptr 가져 오기 및 다시 공유하기

class A {}; 

void f(A* a) { 
    shared_ptr<A> c(a); 
} 

int main() { 
    auto a = make_shared<A>(); 
    auto b = a.get(); 
    f(b); 
    return 0; 
} 

f의 끝 부분에서 내 프로그램이 충돌합니다. 무엇이 이것을 일으킬 수 있습니까? 삭제하려고하는 것이 있고 존재하지 않는 것이 있습니까?

답변

5

동일한 리소스를 관리하려고하는 두 개의 관련없는 공유 포인터가 있습니다. 그것은 정의되지 않은 행동으로 이어집니다. 특히 이들은 둘 다 범위를 벗어날 때 리소스를 삭제하려고 시도합니다.

일반적으로, 단지 이렇게하지 : 여기에서 일어나고있는 것은 초기 make_shared()A을 소유하고 shared_ptr를 만드는 것입니다

+0

올리버가 맞습니다. 이러지 마! 'std :: shared_ptr'는 동일한 shared_ptr이 서로를 인식하고있는 한 동일한 sharling을 허용합니다. 원시 포인터를 꺼내고 다른 shared_ptr에 소유권을 부여하자마자 각각의 소유주가 독점권을 가지고 있다는 것을 알고있는 독립 소유자가 있습니다 (또는 shared_ptr의 경우 공유 된 연합 소유권이며 두 개의 분리 된 소유자가 있습니다). "연합"). – Eljay

2
class A {}; 

void f(A* a) { 
    shared_ptr<A> c(a); 
} 

int main() { 
    auto a = make_shared<A>(); 
    auto b = a.get(); 
    f(b); 
    return 0; 
} 

. f(b)에 전화하면 같은 데이터를 소유하고 있다고 생각하는 관련없는 두 번째 공유 포인터가 생성됩니다. 함수 호출 f()이 끝나면 로컬 공유 ptr 변수가 삭제됩니다. 이는 참조 카운트가 0인지 여부를 확인하므로 객체를 삭제합니다. 그런 다음 주 함수가 끝나면 로컬 변수 a에 대한 소멸자가 실행되고 참조 횟수가 0 (다시 계산 됨)인지 확인하여 동일한 데이터를 두 번 삭제하려고합니다. 이 이중 삭제는 충돌을 일으키는 원인입니다.

두 가지 해결책이 있습니다. 가장 쉬운 방법은 원시 포인터를 처리하지 않고 을 f()에 직접 전달하는 것입니다. 그러면 참조 계산이 올바르게 작동하고 데이터가 한 번만 파괴됩니다.

또 다른 방법은 A 클래스를 std::enable_shared_from_this으로 공개적으로 상속받는 것입니다. 즉

class A : public std::enable_shared_from_this<A> {}; 

void f(A* a) { 
    shared_ptr<A> c = a->shared_from_this(); 
} 

당신은 약 enable_shared_from_thishere를 읽을 수 있습니다 그럼 당신은, 원시 포인터에서 (올바른 참조 카운팅) 공유 포인터를 "복구"로 shared_from_this() 방법을 사용할 수 있습니다.

관련 문제