배열과 함께 unique_ptr을 사용합니까? p(new int[10]); 그러나 필요합니까?

std::unique_ptr 예를 들어 배열을 지원합니다.

std::unique_ptr<int[]> p(new int[10]);

그러나 필요합니까? 아마도 사용하는 것이 더 편리하다 std::vectorstd::array.

그 구조에 대한 사용을 찾으십니까?



답변

일부 사람들은 std::vector할당자를 사용 하더라도 고급 기능을 사용할 수 없습니다 . 어떤 사람들은 동적 크기의 배열을 필요로 std::array합니다. 그리고 어떤 사람들은 배열을 반환하는 것으로 알려진 다른 코드에서 배열을 얻습니다. 그 코드는 vector또는 다른 것을 반환하기 위해 다시 작성되지 않습니다 .

을 허용 unique_ptr<T[]>하면 해당 요구 를 처리 할 수 있습니다.

요컨대, 필요할unique_ptr<T[]> 때 사용 합니다. 대안이 단순히 효과가 없을 때. 최후의 수단입니다.


답변

트레이드 오프가 있으며 원하는 것과 일치하는 솔루션을 선택합니다. 내 머리 꼭대기에서 :

초기 크기

  • vector그리고 unique_ptr<T[]>크기는 실행 시간에 지정할 수 있습니다
  • array 컴파일시 크기 만 지정할 수 있습니다.

크기 조정

  • arrayunique_ptr<T[]>크기 조정 허용하지 않습니다
  • vector 않습니다

저장

  • vectorunique_ptr<T[]>(일반적 힙) 객체 외부에 데이터를 저장할
  • array 객체에 데이터를 직접 저장

사자

  • array그리고 vector복사를 허용
  • unique_ptr<T[]> 복사를 허용하지 않습니다

스왑 / 이동

  • vectorunique_ptr<T[]>O (1)이 시간 swap및 이동 동작을
  • arrayO (n) 시간 swap및 이동 연산이 있으며 여기서 n은 배열의 요소 수입니다.

포인터 / 참조 / 반복자 무효화

  • array 객체가 활성화되어있는 동안에도 포인터, 참조 및 반복자가 무효화되지 않도록합니다. swap()
  • unique_ptr<T[]>반복자가 없습니다. 포인터와 참조는 swap()객체가 활성화되어있는 동안에 만 무효화됩니다 . 스와핑 한 후에는 포인터가 스왑 한 배열을 가리 키므로 여전히 그런 의미에서 “유효”합니다.
  • vector 재 할당에서 포인터, 참조 및 반복자를 무효화 할 수 있습니다 (재 할당이 특정 작업에서만 발생할 수 있음을 보장합니다).

개념 및 알고리즘과의 호환성

  • array그리고 vector둘 다 컨테이너입니다
  • unique_ptr<T[]> 컨테이너가 아닙니다

정책 기반 설계로 리팩토링 할 수있는 기회 인 것 같습니다.


답변

a를 사용하는 한 가지 이유 는 배열 unique_ptr값을 초기화 하는 런타임 비용을 지불하고 싶지 않기 때문 입니다.

std::vector<char> vec(1000000); // allocates AND value-initializes 1000000 chars

std::unique_ptr<char[]> p(new char[1000000]); // allocates storage for 1000000 chars

std::vector생성자와 std::vector::resize()초기화 값 것이다 T– 그러나 new경우는 그렇게하지 않을 것이다 T포드입니다.

C ++ 11 및 std :: vector 생성자의 Value-Initialized Objects 참조

참고 vector::reserve여기에 대안이 아니다는 : 표준 : : 벡터 후에 원시 포인터에 액세스 :: 예비 안전?

그것은 C 프로그래머가 선택할 수 같은 이유 malloc이상 calloc.


답변

std::vector동안, 주변에 복사 할 수 있습니다 unique_ptr<int[]>배열의 고유 한 소유권을 표현 할 수 있습니다. std::array반면에, 컴파일 타임에 크기를 결정해야하므로 일부 상황에서는 불가능할 수 있습니다.


답변

Scott Meyers는 Effective Modern C ++에서 다음과 같이 말합니다.

의 존재 std::unique_ptr배열이 있기 때문에, 당신 만 지적 관심을해야한다 std::array,
std::vector,std::string 거의 항상 원시 배열보다 더 나은 데이터 구조의 선택입니다. 내가 std::unique_ptr<T[]>이해할 수있는 유일한 상황에 대해서는 소유권이 있다고 가정하는 힙 배열에 대한 원시 포인터를 반환하는 C와 같은 API를 사용하는 경우가 될 것입니다.

Charles Salvia의 대답은 관련이 있다고 생각합니다 std::unique_ptr<T[]>. 컴파일시 크기를 알 수없는 빈 배열을 초기화하는 유일한 방법입니다. Scott Meyers는 이러한 사용 동기에 대해 무엇을 말해야 std::unique_ptr<T[]>합니까?


답변

반대로 std::vector하고 std::array, std::unique_ptrNULL 포인터를 소유 할 수 있습니다.
이것은 배열 또는 NULL을 기대하는 C API로 작업 할 때 유용합니다.

void legacy_func(const int *array_or_null);

void some_func() {
    std::unique_ptr<int[]> ptr;
    if (some_condition) {
        ptr.reset(new int[10]);
    }

    legacy_func(ptr.get());
}

답변

내가 사용했던 unique_ptr<char[]>게임 엔진에 사용되는 사전 할당 된 메모리 풀을 구현 할 수 있습니다. 아이디어는 충돌 요청 결과 및 각 프레임에서 메모리를 할당 / 해제하지 않고도 입자 물리와 같은 다른 것들을 반환하기 위해 동적 할당 대신 사용되는 미리 할당 된 메모리 풀을 제공하는 것입니다. 파괴 논리가 필요하지 않은 (메모리 할당 해제 만) 제한된 수명 시간 (일반적으로 1, 2 또는 3 프레임)으로 객체를 할당하기 위해 메모리 풀이 필요한 이러한 종류의 시나리오에는 매우 편리합니다.