고유 한 shared_ptr
인스턴스 의 요점은 이것이 shared_ptr
범위 내에있는 한 참조 횟수가 1 이상이기 때문에 가리키는 개체가 계속 존재 하도록 (가능한 한) 보장 하는 것입니다.
Class::only_work_with_sp(boost::shared_ptr<foo> sp)
{
// sp points to an object that cannot be destroyed during this function
}
따라서에 대한 참조를 사용하여 shared_ptr
해당 보장을 비활성화합니다. 따라서 두 번째 경우 :
Class::only_work_with_sp(boost::shared_ptr<foo> &sp) //Again, no copy here
{
...
sp->do_something();
...
}
sp->do_something()
널 포인터로 인해 폭발 하지 않을 것이라는 것을 어떻게 알 수 있습니까?
그것은 모두 코드의 '...'섹션에 무엇이 있는지에 달려 있습니다. shared_ptr
동일한 객체에 대한 a 를 지우는 부작용 (코드의 다른 부분)이있는 첫 번째 '...'중에 무언가를 호출하면 어떻게 됩니까? 그리고 그것이 shared_ptr
그 물체에 남아있는 유일한 유일한 것이면 어떻게 될까요? Bye bye object, 당신이 시도하고 사용하려는 곳.
따라서이 질문에 답하는 방법에는 두 가지가 있습니다.
함수 본체에서 개체가 죽지 않을 것이라는 확신이들 때까지 전체 프로그램의 소스를 매우주의 깊게 조사하십시오.
매개 변수를 다시 참조 대신 고유 한 개체로 변경합니다.
여기에 적용되는 일반적인 조언 : 프로파일 러에서 현실적인 상황에서 제품의 시간을 정하고 변경하려는 변경 사항이 성능에 큰 차이가 있습니다.
댓글 작성자 JQ 업데이트
여기에 인위적인 예가 있습니다. 의도적으로 간단하므로 실수는 분명합니다. 실제 예에서 실수는 실제 세부 사항의 레이어에 숨겨져 있기 때문에 그다지 분명하지 않습니다.
어딘가에 메시지를 보내는 기능이 있습니다. 큰 메시지 일 수 있으므로 std::string
여러 장소로 전달 될 때 복사 될 가능성이 있는 a 를 사용하는 대신 a shared_ptr
to 문자열을 사용 합니다.
void send_message(std::shared_ptr<std::string> msg)
{
std::cout << (*msg.get()) << std::endl;
}
(이 예제에서는 콘솔로 "보내기"만하면됩니다).
이제 이전 메시지를 기억하는 기능을 추가하려고합니다. 우리는 다음과 같은 동작을 원합니다. 가장 최근에 보낸 메시지를 포함하는 변수가 존재해야하지만 현재 메시지가 전송되는 동안에는 이전 메시지가 없어야합니다 (변수는 보내기 전에 재설정되어야 함). 따라서 새 변수를 선언합니다.
std::shared_ptr<std::string> previous_message;
그런 다음 지정한 규칙에 따라 기능을 수정합니다.
void send_message(std::shared_ptr<std::string> msg)
{
previous_message = 0;
std::cout << *msg << std::endl;
previous_message = msg;
}
따라서 전송을 시작하기 전에 현재 이전 메시지를 삭제하고 전송이 완료된 후 새 이전 메시지를 저장할 수 있습니다. 문제 없다. 다음은 몇 가지 테스트 코드입니다.
send_message(std::shared_ptr<std::string>(new std::string("Hi")));
send_message(previous_message);
예상대로 이것은 Hi!
두 번 인쇄 됩니다.
이제 코드를보고 생각하는 메인테이너 씨가 따라옵니다.이 매개 변수 send_message
는 다음과 shared_ptr
같습니다.
void send_message(std::shared_ptr<std::string> msg)
분명히 다음과 같이 변경할 수 있습니다.
void send_message(const std::shared_ptr<std::string> &msg)
이것이 가져올 성능 향상을 생각하십시오! (일부 채널을 통해 일반적으로 큰 메시지를 보내려고하므로 성능 향상이 측정 할 수 없을 정도로 작습니다.)
그러나 실제 문제는 이제 테스트 코드가 정의되지 않은 동작을 표시한다는 것입니다 (Visual C ++ 2010 디버그 빌드에서는 충돌이 발생 함).
유지 관리자는 이에 놀랐지 만 send_message
문제 발생을 막기 위해 방어 검사를 추가합니다 .
void send_message(const std::shared_ptr<std::string> &msg)
{
if (msg == 0)
return;
그러나 물론 호출 msg
될 때 null이 아니기 때문에 여전히 진행되고 충돌 send_message
합니다.
내가 말했듯이 모든 코드가 사소한 예에서 너무 가깝기 때문에 실수를 쉽게 찾을 수 있습니다. 그러나 서로에 대한 포인터를 개최 가변 객체 사이의 더 복잡한 관계와 실제 프로그램에서, 쉽게 만드는 실수를 감지하는 데 필요한 테스트 케이스를 구성하는 실수를, 하드.
함수가 shared_ptr
계속해서 null이 아닌 것에 의존 할 수 있기를 원하는 쉬운 솔루션 은 함수가 shared_ptr
기존에 대한 참조에 의존하는 대신 자체 true를 할당 하는 것 shared_ptr
입니다.
단점은 복사 된 a shared_ptr
가 자유롭지 않다는 것입니다. "잠금없는"구현도 스레딩 보장을 준수하기 위해 연동 된 작업을 사용해야합니다. 따라서 a shared_ptr
를 .txt 파일로 변경하여 프로그램 속도를 크게 높일 수있는 상황이있을 수 있습니다 shared_ptr &
. 그러나 이것은 모든 프로그램에 안전하게 적용 할 수있는 변경 사항은 아닙니다. 프로그램의 논리적 의미를 변경합니다.
std::string
대신 std::shared_ptr<std::string>
, 대신 전체를 사용하면 유사한 버그가 발생합니다 .
previous_message = 0;
메시지를 정리하기 위해 다음과 같이 말했습니다.
previous_message.clear();
그런 다음 증상은 정의되지 않은 동작 대신 실수로 빈 메시지를 보내는 것입니다. 매우 큰 문자열의 추가 복사본 비용은를 복사하는 비용보다 훨씬 클 shared_ptr
수 있으므로 절충안이 다를 수 있습니다.