QVector 대 QList


80

반복해야하는 정수 목록이 있지만 배열이 부적절합니다. 무슨 사이의 차이점은 vectors그리고 lists내가 유형을 선택하기 전에 내가 알 필요가 무엇입니까?

명확하게 말하면 QT 문서를 읽었지만 이것이 내가 아는 범위입니다.

QList<T>, QLinkedList<T>QVector<T>유사한 기능을 제공합니다. 다음은 개요입니다.

  • 대부분의 경우 사용 QList하기에 적합한 클래스입니다. 인덱스 기반 API는 QLinkedList's반복자 기반 API보다 편리하며 일반적으로 QVector항목을 메모리에 저장하는 방식 보다 빠릅니다 . 또한 실행 파일에서 더 적은 코드로 확장됩니다.
  • 목록 중간에 일정한 시간 삽입을 보장하고 인덱스가 아닌 항목에 대한 반복기를 보장하는 실제 연결 목록이 필요한 경우 QLinkedList.
  • 항목이 인접한 메모리 위치를 차지하도록하려면을 사용하십시오 QVector.

답변:


122

QVectorstd::vector이름에서 짐작할 수 있듯이 는 대부분과 유사합니다 . 와의 명백한 연관성에도 불구하고에 QList더 가깝 boost::ptr_deque습니다 std::list. 개체를 직접 저장하지 않고 대신 개체에 대한 포인터를 저장합니다. 양쪽 끝에서 빠른 삽입의 모든 이점을 얻고 재 할당에는 복사 생성자 대신 포인터를 섞는 것이 포함되지만 실제 std::deque또는 의 공간적 지역성을 잃고 std::vector많은 힙 할당을 얻습니다. 작은 개체에 대한 힙 할당을 피하고 공간적 지역성을 되찾기 위해 몇 가지 의사 결정을 내렸지 만 내가 이해하는 바에 따르면 int.

QLinkedList와 유사하며 std::list모든 단점이 있습니다. 일반적으로 이것은 컨테이너의 마지막 선택이어야합니다.

QT 라이브러리는 QList객체 사용을 매우 선호하므로 자신의 코드에서 객체를 선호하면 때때로 불필요한 지루함을 피할 수 있습니다. 추가 힙 사용 및 실제 데이터의 임의 위치 지정은 이론적으로 일부 상황에서 손상 될 수 있지만 종종 눈에 띄지 않습니다. 그래서 QList프로파일 링이 QVector. 연속 할당이 중요 할 것으로 예상하는 경우 [읽기 : a T[]대신 a를 예상하는 코드와 인터페이싱하고 QList<T>있으며 이는 QVector바로 시작하는 이유가 될 수 있습니다 .


일반적으로 컨테이너에 대해 질문하고 QT 문서를 참조로 사용했다면 위의 정보는 유용하지 않습니다.

std::vector크기를 조정할 수있는 배열입니다. 모든 요소는 나란히 저장되며 개별 요소에 빠르게 액세스 할 수 있습니다. 단점은 삽입이 한쪽 끝에서만 효율적이라는 것입니다. 중간이나 시작 부분에 무언가를 놓으면 공간을 만들기 위해 다른 개체를 복사해야합니다. big-oh 표기법에서 끝에 삽입은 O (1), 다른 곳에 삽입은 O (N), 랜덤 액세스는 O (1)입니다.

An std::deque은 비슷하지만 객체가 나란히 저장된다는 보장은 없으며 양쪽 끝의 삽입이 O (1)이되도록합니다. 또한 한 번에 더 작은 메모리 청크를 할당해야하는데, 이는 때때로 중요 할 수 있습니다. 임의 액세스는 O (1)이고 중간 삽입은 O (N) vector입니다. 공간적 지역 성은보다 나쁘지만 std::vector개체가 클러스터되는 경향이 있으므로 몇 가지 이점을 얻을 수 있습니다.

An std::list은 연결된 목록입니다. 세 가지 표준 순차 컨테이너의 메모리 오버 헤드가 가장 많이 필요하지만 삽입해야 할 위치를 미리 알고 있다면 어디든 빠르게 삽입 할 수 있습니다. 개별 요소에 대한 임의 액세스를 제공하지 않으므로 O (N)에서 반복해야합니다. 그러나 일단 거기에 실제 삽입은 O (1)입니다. 가장 큰 이점 std::list은 빠르게 연결할 수 있다는 것입니다. 전체 값 범위를 다른 값으로 이동 std::list하면 전체 작업이 O (1)입니다. 또한 때때로 중요 할 수있는 목록에 대한 참조를 무효화하는 것이 훨씬 더 어렵습니다.

일반적 으로 원시 배열이 필요한 라이브러리에 데이터를 전달할 수 있어야하는 경우가 아니면를 선호 std::deque합니다 std::vector. std::vector연속적으로 보장되므로이 &v[0]목적을 위해 작동합니다. 마지막으로를 사용했던 때가 기억 나지 std::list않지만 유효하게 남아있는 참조에 대해 더 강력한 구아 레티가 필요했기 때문에 거의 확실했습니다.


FWIW, std :: deque는 참조에 대해 꽤 좋은 보증을 제공합니다. 반복자는 쉽게 무효화되지만 멤버에 대한 포인터는 대기열에서 빼기 작업에 매우 강력합니다.
Ben

좋은 대답입니다. 그러나 추가 질문이 있습니다. 어느 것이 반복하는 것이 더 빠릅니까? 객체 세트가 있는데 실제로 삽입되거나 제거되지는 않지만 가능한 한 빨리 객체를 반복해야합니다. 어느 것이 더 빠릅니까?
birgersp

좋은 정보. 다음 문장이 가장 유용하다는 것을 알았습니다. "QT 라이브러리는 QList 객체의 사용을 매우 선호합니다". 내 사용 사례에서는 QList 및 QListString을 좋아하는 QTableWidget을 다루고 있습니다. 따라서 사용 사례가 QVector와 QList 사이의 결정을 지시하도록하십시오.
panofish

1
당신은에 대해 날카로운 벤치마킹 std::dequestd::vector했습니까? 당신은 ... 놀라게 될 것입니다
마크 Mutz - mmutz

4
Qt 개발자가 QList가 기본 컨테이너로 권장되지 않는다는 불만을 제기 한 후 문서가 업데이트되었습니다. 이제 다음과 같이 표시됩니다. " QVector 가 기본 첫 번째 선택이어야합니다. [...] 그러나 QList 는 매개 변수 전달 및 값 반환을 위해 Qt API 전체에서 사용됩니다. QList 를 사용하여 해당 API와 인터페이스합니다. " (QList 문서)
AntonyG

64

여러가지가 바뀌었다

우리는 이제 Qt 5.8에 있으며 상황이 변경되었으므로 문서가 변경되었습니다. 이 질문에 대해 명확하고 다른 대답을 제공합니다.

QVector기본 첫 번째 선택이어야합니다. QVector<T>일반적으로보다 더 나은 성능을 제공합니다 QList<T때문에>, QVector<T>항상 메모리에 순차적으로 해당 항목을 저장하는 곳 QList<T>하지 않는 한 힙에 해당 항목을 할당 할 것 sizeof(T) <= sizeof(void*)중 하나가 될 T 선언되었으며 Q_MOVABLE_TYPE또는이 Q_PRIMITIVE_TYPE사용을 Q_DECLARE_TYPEINFO .

QList설명 은 사용의 장단점을 참조하십시오 . 그러나 QList매개 변수를 전달하고 값을 반환하기 위해 Qt API 전체에서 사용됩니다. QList해당 API와 인터페이스하는 데 사용 합니다.


2
이것은 올라갈 것이고 이제 대답으로 받아 들여 져야합니다.
ymoreau

12

In QVectorstd::vector. QLinkedList와 유사합니다 std::list. QList인덱스 기반 벡터이지만 메모리 위치는 보장되지 않습니다 (예 std::deque:).


3

QtList 문서에서 :

  • 대부분의 경우에 사용되는 QList. 수천 개의 항목이있는 구조의 경우 중간에 효율적으로 삽입 할 수 있으며 인덱싱 된 액세스를 제공합니다. prepend()append()매우 빠른 메모리가 보낸 내부 배열의 양단에 미리 할당된다. QList<T>T 유형의 포인터 배열입니다. T에 포인터 또는 Qt 공유 유사 포인터 유형이있는 경우 객체는 배열에 직접 저장됩니다.

  • QVector단일 힙 할당에서 항목에 대한 메모리를 할당하기 때문에 포인터보다 크기가 큰 새 항목 이 많 append()거나 많은 경우 선호됩니다 . 들어 새로운 항목이 추가 인 삽입, 힙에 새 항목의 메모리 할당이 필요합니다. 간단히 말해, 항목이 인접한 메모리 위치를 차지하도록하거나 항목이 포인터보다 크고 삽입시 개별적으로 힙에 할당하는 오버 헤드를 피하려면을 사용하십시오 .insert()QVectorQListQVector


-2

QVector 크기를 변경 (증가 또는 감소) 할 수있는 어레이와 같지만 많은 트랜잭션과 계산 및 시간이 수반됩니다.

예를 들어 항목을 추가하려는 경우 새 배열이 생성되고 모든 항목이 새 배열에 복사되고 새 항목이 끝에 추가되고 이전 배열이 삭제됩니다. 그 반대도 마찬가지입니다.

그러나 QLinkedList포인터로 작동합니다. 따라서 새 항목이 생성되면 새 메모리 공간 만 할당되고 유일한 메모리 청크에 연결됩니다. 포인터와 함께 작동하기 때문에 더 빠르고 효율적입니다.

크기를 많이 변경하지 않을 것으로 예상되는 항목 목록이 있으면 좋을 수 QVector있지만 일반적으로 QLinkedList대부분의 용도로 사용됩니다.


3
-1 : QVector는 미리 할당하고 추가 및 팝을위한 좋은 성장 / 축소 전략을 가지고 있기 때문에 사용자가 주장하는 것처럼 무거운 트랜잭션을 제공하지 않습니다. 접두사 / 삽입은 실제로 데이터 범위 이동이 필요하지만 메모리에서 연속적이기 때문에 매우 빠르게 수행됩니다 (캐시는 QList와 같이 분산 된 힙 청크와 달리 연속 데이터에서 잘 작동 할 수 있음). QLinkedList가 대부분의 목적으로 사용된다는 두 번째 진술은 분명히 잘못되었습니다. 가장 드물게 사용됩니다. QList와 혼동 할 수 있습니까?
DerManu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.