새로운 std :: make_unique와 std :: unique_ptr의 차이점


130

않습니다 std::make_unique 와 같은 효율성 이점이 std::make_shared있습니까?

수동 구성 std::unique_ptr과 비교하여 :

std::make_unique<int>(1);         // vs
std::unique_ptr<int>(new int(1));

않는 make_shared어떤 효율성 단지 긴 손으로 코드를 작성하는 동안이?
Ed Heal

9
@EdHeal make_shared단일 할당에서 개체 공간과 제어 블록 공간을 함께 할당 할 수 있기 때문 입니다. 그 비용은 개체를 제어 블록과 별도로 할당 해제 할 수 없기 때문에 weak_ptr많은 양을 사용하면 더 많은 메모리를 사용할 수 있습니다.
bames53

아마도 이것은 좋은 출발점이 될 것입니다. stackoverflow.com/questions/9302296/…
Ed Heal

답변:


140

뒤에 동기 make_unique는 주로 두 가지입니다.

  • make_unique명시 적으로 사용 new하면 명명되지 않은 임시를 사용하지 않는 규칙을 기억해야합니다.

    foo(make_unique<T>(), make_unique<U>()); // exception safe
    
    foo(unique_ptr<T>(new T()), unique_ptr<U>(new U())); // unsafe*
  • make_unique마지막으로 '를 추가 하면'을 제외하고 new는 '사용하지 마십시오'라는 이전 규칙이 아닌 '사용 하지 않음'을 사람들에게 알릴 수 있습니다 .newunique_ptr

세 번째 이유도 있습니다.

  • make_unique중복 유형 사용이 필요하지 않습니다. unique_ptr<T>(new T())->make_unique<T>()

그 이유 중 어느 것도 사용 make_shared하지 않는 방식으로 런타임 효율성을 개선하는 것과 관련 이 없습니다 (잠재적 인 최대 메모리 사용 비용으로 두 번째 할당을 피하기 때문에).

* C ++ 17에는 더 이상 안전하지 않은 규칙 변경이 포함될 것으로 예상됩니다. C ++위원회 보고서 P0400R0P0145R3을 참조하십시오 .


말하는 것이 더 합리적 std::unique_ptr이며 std::shared_ptr사람들에게 "사용하지 말라고"말할 수있는 이유 new입니다.
Timothy Shields

2
@TimothyShields 그래, 그게 내 뜻이야. 그것은 11 C ++로 우리가 단지이다 make_shared그래서 make_unique이전에 실종 된 마지막 조각입니다.
bames53

1
명명되지 않은 임시를 사용하지 않는 이유를 간략하게 언급하거나 링크 할 수있는 방법이 있습니까?
Dan Nissenbaum

14
사실에서 stackoverflow.com/a/19472607/368896 , 나는 그것이 ... 그 대답에서 다음 함수 호출을 고려있어 f: f(unique_ptr<T>(new T), function_that_can_throw());- : 대답 인용 (위해) 컴파일러가 호출 허용된다 : new T, function_that_can_throw(), unique_ptr<T>(...). 물론 경우에 function_that_can_throw실제로 발생 당신은 누출. make_unique이 경우를 방지합니다. 그래서 내 질문에 대답했습니다.
Dan Nissenbaum

3
한 번 std :: unique_ptr <T> (new T ())를 사용해야했던 한 가지 이유는 T의 생성자가 비공개이기 때문입니다. std :: make_unique에 대한 호출이 클래스 T의 공용 팩토리 메소드에 있더라도 std :: make_unique의 기본 메소드 중 하나가 개인 생성자에 액세스 할 수 없으므로 컴파일되지 않았습니다. std :: make_unique의 구현에 의존하고 싶지 않기 때문에 그 메소드를 친구로 만들고 싶지 않았습니다. 그래서 유일한 해결책은 클래스 T의 팩토리 메소드에서 new를 호출 한 다음 std :: unique_ptr <T>에 래핑했습니다.
Patrick

14

std::make_unique그리고 std::make_shared두 가지 이유가 있습니다 :

  1. 따라서 템플릿 유형 인수를 명시 적으로 나열 할 필요가 없습니다.
  2. 사용 std::unique_ptr또는 std::shared_ptr생성자에 대한 추가 예외 안전 . ( 여기 노트 섹션을 참조 하십시오 .)

실제로 런타임 효율성에 관한 것이 아닙니다. 제어 블록과 T할당 에 대한 내용이 한꺼번에 있지만, 이러한 기능이 존재하는 동기는 더 적고 동기 부여가 적습니다.


또한 예외 안전을 위해 존재합니다.
0x499602D2

@ 0x499602D2 그리고 좋은 추가. 이 페이지는 그것에 대해 이야기합니다.
Timothy Shields

미래 독자들을 위해 C ++ 17은 함수 인수의 인터리빙을 허용하지 않으므로 예외 안전에 대한 인수는 더 이상 유지되지 않습니다. 두 개의 병렬에 대한 메모리 할당 std::make_shared은 다른 메모리 할당이 발생하기 전에 그 중 하나 이상이 스마트 포인터에 랩핑되어 누출이 없도록합니다.
MathBunny

7

대신 std::unique_ptr(new A())또는 std::shared_ptr(new A())직접 대신 사용해야하는 이유 는 현재 범위를 벗어난 std::make_*()클래스의 생성자에 액세스 할 수 없기 때문 A입니다.


0

함수 호출 고려

void function(std::unique_ptr<A>(new A()), std::unique_ptr<B>(new B())) { ... }

new A()는 성공하지만 new B()는 예외를 던진다 고 가정 하십시오. 프로그램의 정상적인 실행을 재개하기 위해 잡습니다. 불행히도 C ++ 표준은 객체 A가 파괴되고 메모리 할당이 해제 될 것을 요구하지 않습니다. A와 B를 포장 std::make_uniques하면 누출이 발생하지 않습니다.

void function(std::make_unique<A>(), std::make_unique<B>()) { ... }

여기서 포인트는 것입니다 std::make_unique<A>std::make_unique<B>소멸자이 발생됩니다 메모리가 해제 : 이제 임시 개체이며, 임시 개체의 정리가 제대로 C에 지정된 ++ 표준. 따라서 가능하면 항상 std::make_uniqueand를 사용하여 객체를 할당하는 것을 선호하십시오 std::make_shared.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.