차이점은 std::make_shared
하나의 힙 할당 을 수행하는 반면 std::shared_ptr
생성자를 호출하면 2를 수행 한다는 것 입니다.
힙 할당은 어디에서 발생합니까?
std::shared_ptr
두 엔티티를 관리합니다.
- 제어 블록 (참조 횟수, 유형 소거 삭제 기 등의 메타 데이터 저장)
- 관리되고있는 객체
std::make_shared
제어 블록과 데이터 모두에 필요한 공간을 단일 힙 할당 계정으로 수행합니다. 다른 경우 new Obj("foo")
에는 관리되는 데이터에 대한 힙 할당을 호출하고 std::shared_ptr
생성자는 제어 블록에 대해 또 다른 힙 할당을 수행합니다.
자세한 정보 는 cppreference 에서 구현 정보를 확인하십시오 .
업데이트 I : 예외 안전
참고 (2019/08/30) : 함수 인수의 평가 순서가 변경되어 C ++ 17부터 문제가되지 않습니다. 특히 함수에 대한 각 인수는 다른 인수를 평가하기 전에 완전히 실행해야합니다.
OP가 예외 안전 측면에 대해 궁금해하는 것처럼 보이기 때문에 대답을 업데이트했습니다.
이 예를 고려하십시오.
void F(const std::shared_ptr<Lhs> &lhs, const std::shared_ptr<Rhs> &rhs) { /* ... */ }
F(std::shared_ptr<Lhs>(new Lhs("foo")),
std::shared_ptr<Rhs>(new Rhs("bar")));
C ++에서는 하위 표현식의 임의의 평가 순서를 허용하므로 한 가지 가능한 순서는 다음과 같습니다.
new Lhs("foo"))
new Rhs("bar"))
std::shared_ptr<Lhs>
std::shared_ptr<Rhs>
이제 2 단계에서 예외가 발생한다고 가정합니다 (예 : 메모리 부족 예외, Rhs
생성자가 일부 예외 발생). 그런 다음 1 단계에서 할당 된 메모리가 손실됩니다. 메모리를 정리할 기회가 없었기 때문입니다. 여기서 문제의 핵심은 원시 포인터가 std::shared_ptr
생성자에게 즉시 전달되지 않았다는 것 입니다.
이 문제를 해결하는 한 가지 방법은 이러한 임의의 순서가 발생하지 않도록 별도의 줄에서 수행하는 것입니다.
auto lhs = std::shared_ptr<Lhs>(new Lhs("foo"));
auto rhs = std::shared_ptr<Rhs>(new Rhs("bar"));
F(lhs, rhs);
물론이 문제를 해결하기 위해 선호되는 방법은 std::make_shared
대신 사용하는 것입니다.
F(std::make_shared<Lhs>("foo"), std::make_shared<Rhs>("bar"));
업데이트 II : 단점 std::make_shared
인용 Casey 의 의견 :
할당은 하나뿐이므로 제어 블록을 더 이상 사용하지 않을 때까지 포인트의 메모리를 할당 해제 할 수 없습니다. A weak_ptr
는 제어 블록을 무기한으로 유지할 수 있습니다.
의 인스턴스가 weak_ptr
제어 블록을 활성 상태로 유지하는 이유는 무엇 입니까?
weak_ptr
s가 관리 대상 개체가 여전히 유효한지 확인 하는 방법이 있어야 합니다 (예 : for lock
). shared_ptr
제어 블록에 저장된 관리 대상 개체를 소유 한 수를 확인하여이를 수행합니다 . 그 결과 shared_ptr
카운트와 weak_ptr
카운트가 모두 0에 도달 할 때까지 제어 블록이 활성화 됩니다.
돌아가다 std::make_shared
이후 std::make_shared
상기 제어 블록 및 관리 개체 모두 단일 힙 할당하게 제어 블록 메모리와 별도로 관리 오브젝트를 확보 할 수있는 방법이 없다. 제어 블록과 관리 대상 개체를 모두 해제 할 수있을 때까지 기다려야합니다.이 개체는 존재하지 shared_ptr
않거나 weak_ptr
살아 있지 않을 때까지 발생합니다 .
대신 제어 블록과 관리 객체를 통해 new
및 shared_ptr
생성자 를 통해 두 개의 힙 할당을 수행했다고 가정합니다 . 그런 다음 활성이없는 경우 관리 대상 객체 (이전)에 shared_ptr
대한 메모리를 해제하고 활성 이없는 경우 제어 블록 (이후에)에 대한 메모리를 해제합니다 weak_ptr
.