deque에 벡터 사용을 선호하는 이유


87

이후

  1. 둘 다 인접한 메모리 컨테이너입니다.
  2. 기능면에서 deque는 벡터가 가진 거의 모든 것을 가지고 있습니다. 앞쪽에 삽입하는 것이 더 효율적이기 때문입니다.

왜 whould 사람을 선호 std::vector하는 std::deque?


2
의 Visual C ++ 구현은 std::deque최대 블록 크기가 매우 작기 때문에 (올바르게 기억하면 최대 16 바이트, 아마도 32 바이트) 실제 응용 프로그램에서는 잘 수행되지 않습니다. A deque<T>where sizeof(T) > 8(또는 16? 작은 숫자)는 vector<T*>각 요소가 동적으로 할당되는와 거의 동일한 성능 특성을 갖습니다. 다른 구현은 최대 블록 크기가 다르므로 다른 플랫폼에서 상대적으로 동일한 성능 특성을 가진 코드를 작성하는 것은 deque.
James McNellis 2011 년

13
Deque는 연속적인 메모리 컨테이너가 아닙니다.
Mohamed El-Nakib 2014

@ravil 아니요,이 질문을 가리키는 중복입니다.

1
고정되지 않은 뻔뻔스러운 사실 오류와 질문 (34) 투표의 균형에 앉아 믿기 어려운
underscore_d

2
@underscore_d 그것이 질문 인 이유입니다. 답변이라면 다른 이야기;)
Assimilater

답변:


115

A의 요소 deque입니다 하지 메모리에 연속; vector요소가 보장됩니다. 따라서 연속 배열이 필요한 일반 C 라이브러리와 상호 작용해야하거나 공간적 지역성에 대해 (많은) 관심이 있다면 vector. 또한 추가 부기가 있으므로 다른 작업은 동등한 vector작업 보다 (약간) 더 비쌉니다 . 반면에 많은 / 대규모 인스턴스를 사용 vector하면 불필요한 힙 조각화 가 발생할 수 있습니다 (에 대한 호출 속도 저하 new).

또한 StackOverflow의 다른 곳에서 지적했듯이 http://www.gotw.ca/gotw/054.htm 에서 더 좋은 토론이 있습니다 .


3
"elsewhere"에 대한 링크가 이제 중단 된 것 같습니다 (조정으로 인해?).
esilk

37

차이점을 알기 위해서는 deque일반적으로 구현되는 방법을 알아야합니다 . 메모리는 동일한 크기의 블록으로 할당되며 함께 연결됩니다 (배열 또는 가능한 벡터로).

따라서 n 번째 요소를 찾으려면 적절한 블록을 찾은 다음 그 안의 요소에 액세스합니다. 이것은 항상 정확히 2 회 조회이기 때문에 일정한 시간이지만 여전히 벡터보다 많습니다.

vector또한 C API이거나 포인터와 길이를 사용할 수 있다는 점에서 더 다재다능하기 때문에 연속 버퍼를 원하는 API 와도 잘 작동합니다. (따라서 아래에 벡터 또는 일반 배열을 가질 수 있으며 메모리 블록에서 API를 호출 할 수 있습니다).

어디 deque가 그것의 가장 큰 장점은 다음과 같습니다

  1. 양쪽 끝에서 컬렉션을 늘리거나 줄일 때
  2. 매우 큰 컬렉션 크기를 다룰 때.
  3. bool을 다룰 때 bitset보다는 bool을 원합니다.

두 번째는 덜 알려져 있지만 매우 큰 컬렉션 크기의 경우 :

  1. 재 할당 비용이 큽니다.
  2. 연속적인 메모리 블록을 찾아야하는 오버 헤드는 제한적이므로 메모리가 더 빨리 부족할 수 있습니다.

과거에 대규모 컬렉션을 처리하고 연속 모델에서 블록 모델로 이동할 때 32 비트 시스템에서 메모리가 부족해지기 전에 컬렉션의 약 5 배를 저장할 수있었습니다. 이는 부분적으로 재 할당 할 때 요소를 복사하기 전에 이전 블록과 새 블록을 실제로 저장해야하기 때문입니다.

이 모든 것을 말하면 std::deque"낙관적 인"메모리 할당을 사용하는 시스템에서 문제가 발생할 수 있습니다 . a의 재 할당을 위해 큰 버퍼 크기를 요청하려는 시도는를 사용하여 vector어느 시점에서 거부 될 수 있지만 bad_alloc, 할당 자의 낙관적 특성은 항상 a가 요청한 더 작은 버퍼에 대한 요청을 허용 할 deque가능성이 높으며 메모리를 확보하기 위해 프로세스를 종료하는 운영 체제. 어느 쪽을 선택하든 너무 즐겁지 않을 수 있습니다.

이러한 경우의 해결 방법은 시스템 수준 플래그를 설정하여 낙관적 할당을 재정의하거나 (항상 가능한 것은 아님) 메모리 사용량을 확인하는 자체 할당자를 사용하거나 이와 유사한 것을 사용하여 메모리를 다소 수동으로 관리하는 것입니다. 분명히 이상적이지 않습니다. (벡터 선호에 대한 귀하의 질문에 답할 수 있습니다 ...)


30

벡터와 deque를 여러 번 구현했습니다. deque는 구현 관점에서 훨씬 더 복잡합니다. 이러한 복잡성은 더 많은 코드와 더 복잡한 코드로 이어집니다. 따라서 벡터보다 deque를 선택하면 일반적으로 코드 크기가 표시됩니다. 또한 코드가 벡터가 뛰어난 기능 (예 : push_back) 만 사용하는 경우 약간의 속도 저하를 경험할 수 있습니다.

양단 대기열이 필요한 경우 deque가 확실한 승자입니다. 그러나 대부분의 삽입과 지우기를 뒤쪽에서 수행하는 경우 벡터가 확실한 승자가 될 것입니다. 확실하지 않은 경우 typedef로 컨테이너를 선언하고 (앞뒤로 쉽게 전환 할 수 있도록) 측정합니다.


3
질문-위원회는 C ++에이 둘의 하이브리드 (예 : "데크")를 추가하는 것을 고려 했습니까? (즉, 이중 종단 vector.) 나는 내 대답 에 아래에 연결된 구현을 작성했습니다 . 속도는 빠르지 vector만 훨씬 더 광범위하게 적용 할 수 있습니다 (예 : 빠른 대기열을 만들 때).
user541686

5

std::deque지속적인 메모리를 보장하지 않으며 인덱스 액세스의 경우 다소 느립니다. 데크는 일반적으로 "벡터 목록"으로 구현됩니다.


14
"벡터 목록"이 옳다고 생각하지 않습니다. "목록"에 대한 정의에 따라 다르지만 대부분의 구현은 "배열에 대한 포인터 벡터"라는 것을 이해했습니다 ( "목록"을 "연결된 목록"으로 읽습니다. , "는 복잡성 요구 사항을 충족하지 않습니다.)
James McNellis 2011 년

2

http://www.cplusplus.com/reference/stl/deque/ 에 따르면 , "벡터와 달리 deque는 연속 된 저장 위치에 모든 요소가 있다고 보장되지 않으므로 포인터 산술을 통한 안전한 액세스 가능성을 제거합니다."

Deques는 부분적으로 연속적인 메모리 레이아웃이 필요하지 않기 때문에 조금 더 복잡합니다. 해당 기능이 필요한 경우 데크를 사용하지 마십시오.

(이전에 내 대답은 표준화의 부족을 가져 왔지만 (위와 동일한 소스에서 "데크는 특정 라이브러리에 의해 다른 방식으로 구현 될 수 있습니다") 실제로 거의 모든 표준 라이브러리 데이터 유형에 적용됩니다.)


5
std::deque보다 덜 표준화되지 않았습니다 std::vector. std::deque연속 스토리지로 복잡성 요구 사항을 충족 할 수 있다고 생각하지 않습니다 .
Jerry Coffin 2011 년

1
아마도 내 표현이 좋지 않았을 것입니다. 표준화가 철저하지 않은 것은 사실이지만, 내가 이해하는 것처럼 벡터는 구성 시퀀스로 표준화되고 데크는 그렇지 않습니다. 그것이 하나의 결정 요인 인 것 같습니다.
pattivacek

1
@JerryCoffin : deque연속 스토리지로 충족 할 수없는 복잡성 요구 사항은 무엇입니까?
user541686

1
@Mehrdad : 솔직히 말해서 내가 생각했던 것이 기억 나지 않습니다. 나는 최근에 나의 이전 코멘트가 틀렸다는 것을 단호하게 말하는 것이 편할 정도로 표준의 그 부분을 보지 않았지만, 지금 그것을보고, 그것이 어떻게 옳을 지 생각할 수 없다.
제리 관

3
@JerryCoffin : 복잡성 요구 사항은 실제로 사소합니다. 큰 배열을 할당하고 시퀀스를 중간에서 바깥쪽으로 밀어 넣을 수 있습니다 (이것이 Mehrdad 구현이하는 일이라고 생각합니다), 끝까지 도달하면 재 할당 할 수 있습니다. 이 접근 방식의 문제는의 요구 사항 중 하나를 충족하지 않는다는 것입니다. deque즉, 끝 부분에 삽입 하면 기존 요소에 대한 참조 가 무효화되지 않습니다 . 이 요구 사항은 불연속 메모리를 의미합니다.
Yakov Galka 2012 년

0

deque는 요소에 대한 임의 액세스를 허용하는 시퀀스 컨테이너이지만 연속 저장소가 있다고 보장되지는 않습니다.


0

각 케이스의 성능 테스트를하는 것이 좋은 생각이라고 생각합니다. 그리고이 테스트에 의존하여 결정을 내립니다.

대부분의 경우 std::deque보다 선호합니다 std::vector.


1
어떤 사실적 오류와 누락 된 단어 중에서 증류 할 수 있는지 질문했다 누군가가 선호하는 것 vector. 우리는 그 이유 가 추론이라고 추론 할 수 있습니다 . deque불특정 테스트에서 알 수없는 이유로 선호한다고 말하는 것은 답이 아닙니다.
underscore_d


0

한편으로 벡터는 deque보다 훨씬 빠릅니다. deque의 모든 기능이 실제로 필요 하지 않은 경우 벡터를 사용하십시오.

반면에 벡터가 제공하지 않는 기능 필요한 경우도 있습니다.이 경우 데크를 사용해야합니다. 예를 들어, deque를 사용하지 않고 알고리즘을 크게 변경하지 않고이 코드 를 다시 작성하도록 시도 합니다.


실제로 동일한 일련의 push_backpop_back작업에서 deque<int>항상 vector<int>내 테스트 보다 20 % 이상 빠릅니다 (O3가있는 gcc). 그게 deque표준 선택 인 이유 인 것 같아요 std::stack...
igel

-1

벡터 메모리는 어레이가 커짐에 따라 재 할당됩니다. 벡터 요소에 대한 포인터가 있으면 유효하지 않게됩니다.

또한 요소를 지우면 반복기가 유효하지 않게됩니다 ( "for (auto ...)"는 아님).

편집 : '데크'를 '벡터'로 변경


-1 : 시작 또는 끝에서 삽입 및 지우기는 다른 요소에 대한 참조 및 포인터를 무효화하지 않습니다. (중간에 삽입 및 지우기가 가능하지만)
Sjoerd

@Sjoerd 나는 그것을 '벡터'로 변경했습니다.
Pierre
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.