왜 std :: move std :: shared_ptr을 사용합니까?
Clang 소스 코드를 살펴본 결과이 스 니펫을 발견했습니다.
void CompilerInstance::setInvocation(
std::shared_ptr<CompilerInvocation> Value) {
Invocation = std::move(Value);
}
왜 내가 원하는 것 ?std::move
std::shared_ptr
공유 리소스에 대한 소유권을 이전 할 수 있습니까?
왜 대신 대신이 작업을 수행하지 않습니까?
void CompilerInstance::setInvocation(
std::shared_ptr<CompilerInvocation> Value) {
Invocation = Value;
}
다른 답변이 충분히 강조하지 않은 것은 속도 의 포인트라고 생각합니다 .
std::shared_ptr
참조 카운트는 atomic 입니다. 기준 카운트를 늘리거나 줄이려면 원자 적 증가 또는 감소 가 필요합니다 . 이것은 원자가 아닌 증가 / 감소 보다 백 배 느리지 만 , 동일한 카운터를 증가시키고 감소 시키면 정확한 수로 감겨 프로세스에 많은 시간과 자원을 낭비한다는 것은 말할 것도 없습니다.
shared_ptr
복사 하는 대신 이동하여 원자 참조 카운트를 "훔치고" 다른 것을 무효화합니다 shared_ptr
. "스틸 링"참조 횟수는 원자 적이 지 않으며 복사하는 것 shared_ptr
(및 원자 참조 증분 또는 감소를 야기) 보다 백 배 빠릅니다 .
이 기술은 최적화를 위해 순수하게 사용됩니다. 복사 (제안한대로)는 기능면에서도 훌륭합니다.
사용 move
하면 주식 수를 늘리고 바로 줄이지 않습니다. 그러면 사용 횟수에 대한 고가의 원자 작업이 절약 될 수 있습니다.
이동 (이동 생성자 등) 작업이 std::shared_ptr
있는 저렴한 가 기본적이기 때문에, "도난 포인터" (소스로부터 목적지에 더욱 정확하게는 온 상태 제어 블록은 레퍼런스 카운트 정보를 포함하는, 소스로부터 목적지로 "도난"된다) .
대신 원자 참조 카운트 증가 (예 : 정수 데이터 멤버뿐만 아니라 Windows 호출)의 복사 작업 은 포인터 / 상태를 훔치는 것 보다 비용 이 많이 듭니다 .std::shared_ptr
++RefCount
RefCount
InterlockedIncrement
따라서이 경우의 참조 횟수 역학을 자세히 분석하십시오.
// shared_ptr<CompilerInvocation> sp;
compilerInstance.setInvocation(sp);
값을 전달한 sp
다음 메소드 내에서 사본 을 가져 오면 다음을 수행 CompilerInstance::setInvocation
할 수 있습니다.
- 메소드를 입력 할 때
shared_ptr
매개 변수는 복사 구성됩니다. ref count atomic incremental . - 메소드 본문 내에서 매개 변수를 데이터 멤버에 복사 합니다
shared_ptr
. ref count atomic incremental . - 메소드를 종료하면
shared_ptr
매개 변수가 삭제됩니다 (ref count atomic decrement) .
총 3 개의 원자 연산에 대해 2 개의 원자 증분과 1 개의 원자 감소가 있습니다.
대신 Clang의 코드에서 올바르게 수행 된 것처럼 shared_ptr
값으로 매개 변수 를 전달한 다음 std::move
메서드 내부에 매개 변수 를 전달하면 다음과 같은 이점이 있습니다.
- 메소드를 입력 할 때
shared_ptr
매개 변수는 복사 구성됩니다. ref count atomic incremental . - 메소드 본문 내에서 데이터 멤버에
std::move
대한shared_ptr
매개 변수 : 참조 횟수는 변경 되지 않습니다 ! 당신은 포인터 / 상태를 훔치고 있습니다 : 비싼 원자 참조 횟수 작업이 필요하지 않습니다. - 메소드를 종료하면
shared_ptr
매개 변수가 삭제됩니다. 그러나 2 단계에서 이동 했으므로shared_ptr
매개 변수가 더 이상 아무것도 가리 키지 않으므로 폐기 할 것이 없습니다. 이 경우에도 원자 감소는 발생하지 않습니다.
결론 :이 경우 하나의 심판 카운트 원자 증분, 즉 하나의 원자 연산 을 얻습니다 .
보시다시피, 이것은 복사 사례에 대해 두 개의 원자 증분과 하나의 원자 감소 (총 세 개의 원자 연산에 대해) 보다 훨씬 낫 습니다 .
를 복사하면 shared_ptr
내부 상태 객체 포인터를 복사하고 참조 횟수를 변경합니다. 그것을 이동하는 것은 포인터를 내부 참조 카운터와 소유 한 객체로 바꾸는 것만 포함하므로 더 빠릅니다.
이 상황에서 std :: move를 사용하는 데는 두 가지 이유가 있습니다. 대부분의 응답은 속도 문제를 해결했지만 코드의 의도를보다 명확하게 보여주는 중요한 문제는 무시했습니다.
std :: shared_ptr의 경우 std :: move는 포인트의 소유권 이전을 분명하게 나타내며 간단한 복사 작업은 추가 소유자를 추가합니다. 물론, 원래 소유자가 그 후에 소유권을 포기하면 (예 : std :: shared_ptr을 파기 할 수있게하여) 소유권 이전이 완료된 것입니다.
std :: move로 소유권을 이전하면 무슨 일이 일어나고 있는지 분명합니다. 일반 사본을 사용하는 경우 원래 소유자가 즉시 소유권을 양도한다는 것을 확인할 때까지 의도 한 작업이 전송인지 확실하지 않습니다. 보너스로, 소유권의 원자 이전은 소유자 수가 1 증가한 임시 상태를 피할 수 있기 때문에보다 효율적인 구현이 가능합니다 (및 참조 수가 변경됨).
참고 URL : https://stackoverflow.com/questions/41871115/why-would-i-stdmove-an-stdshared-ptr
'Programing' 카테고리의 다른 글
System.Web.Mvc가 참조 추가에없는 이유는 무엇입니까? (0) | 2020.07.03 |
---|---|
ES6 맵 / 세트를 병합하는 가장 간단한 방법은 무엇입니까? (0) | 2020.07.03 |
TreeMap을 반복하는 방법? (0) | 2020.07.02 |
파이썬에서 객체 속성을 반복 (0) | 2020.07.02 |
텍스트 상자에 자리 표시 자 텍스트 추가 (0) | 2020.07.02 |