std :: vector 요소는 연속적입니까?


111

내 질문은 간단합니다. std :: vector 요소가 연속적임을 보장합니까? 즉, std :: vector의 첫 번째 요소에 대한 포인터를 C-array로 사용할 수 있습니까?

내 기억이 잘 작동한다면 C ++ 표준은 그런 보장을하지 않았습니다. 그러나 std :: vector 요구 사항은 요소가 인접하지 않은 경우 실제로 충족 할 수 없을 정도였습니다.

누군가 이것을 명확히 할 수 있습니까?

예:

std::vector<int> values;
// ... fill up values

if( !values.empty() )
{
    int *array = &values[0];
    for( int i = 0; i < values.size(); ++i )
    {
        int v = array[i];
        // do something with 'v'
    }
}

valuesif블록 안에서 돌연변이를하면 문제가 있다는 것을 알고 있습니다 . 그래도 질문에 대한 답을 모르기 때문에 댓글을 남기고 있습니다. :)
Greg D

@Greg : 무슨 문제 – 조금 더 자세히 설명 할 수 있습니까?
Reunanen

그는 새로운 값을 푸시하면 배열이 무효화되는 "realloc"이 발생할 수 있음을 의미한다고 생각합니다.
Martin Cote

mutate values, 특히 크기를 변경하는 호출 (예 push_back():)은에 복사 된 포인터를 무효화하는 기본 벡터의 재 할당을 프롬프트 할 수 있습니다 array. 벡터에 대한 포인터 대신 vector :: iterator를 사용하는 것과 동일한 원리입니다. :)
Greg D

1
예, 클래스에 포함 된 값이 아니라 클래스 자체에 대해 이야기하고 있음을 분명히하기 위해`` 's around 값을 넣었습니다. :) 불행한 이름 지정 및 모든 것. 나는이 질문이 관련이있는 일반적인 경우에 실제로 문제가되지 않는다고 생각합니다. 왜 누군가가 메모리에 대한 포인터를 잡고 포인터를 사용하는 대신 벡터를 사용하기 시작합니까? 어리 석음.
Greg D

답변:


118

이것은 C ++ 98 표준에서 누락되었지만 나중에 TR의 일부로 추가되었습니다. 물론 곧 나올 C ++ 0x 표준은이를 요구 사항으로 포함 할 것입니다.

n2798에서 (C ++ 0x 초안) :

23.2.6 클래스 템플릿 벡터 [벡터]

1 벡터는 임의 액세스 반복기를 지원하는 시퀀스 컨테이너입니다. 또한 끝에서 (상각 된) 일정 시간 삽입 및 삭제 작업을 지원합니다. 중간에 삽입하고 지우려면 선형 시간이 걸립니다. 스토리지 관리는 자동으로 처리되지만 효율성 향상을위한 힌트를 제공 할 수 있습니다. 벡터의 요소는 연속적으로 저장됩니다. 즉, v가 T가 bool이 아닌 다른 유형 인 벡터이면 모든 0 <= n <v에 대해 ID & v [n] == & v [0] + n을 따릅니다. .크기().


3
이것은 또한 ISO 14882, 2nd Edition : Section 23.2.4 [lib.vector]에 명시되어 있습니다. "벡터의 요소는 연속적으로 저장됩니다. 즉, v가 vector <T, Allocator>이면 T는 다른 유형입니다. bool이면 모든 0 <= n <v.size ()에 대해 & v [n] == & v [0] + n이라는 신원을 따릅니다. "
Mike Caron

4
그래서 s, TR, TC, :) 사실 C ++ 03은 내가 읽은 것에서 C ++ 98-TC1 (technical corrigendum)이라고도합니다
Johannes Schaub-litb

2
벡터의 벡터는 어떻습니까? 내부 벡터는 마지막 그룹의 내부 벡터 바로 뒤에 있습니까?
huseyin tugrul buyukisik

1
@huseyin tugrul buyukisik 이것에 대한 답을 배웠습니까? 나는 또한 어떻게이 일을 궁금 오전
데이비드 도리아

1
@huseyin tugrul buyukisik 물론 사실이지만 std::vector연속적인 것은 후속 사례입니다 . 예를 들면 :에 std::vector<std::vector<int>> v요소 v[0], v[1]... 메모리에 연속적으로 저장되어 있지만, 요소되어 v[0].back()v[1].front()보장되지 않습니다.
jarzec 2017

27

다른 답변에서 지적했듯이 벡터의 내용은 연속적임을 보장합니다 (bool의 기이함을 제외하고).

제가 추가하고 싶은 코멘트는 벡터에 삽입 또는 삭제를 수행하여 벡터가 메모리를 재 할당 할 수있는 경우 저장된 모든 포인터와 반복기가 무효화되도록한다는 것입니다.


1
요소는 여전히 인접한 메모리 블록에 저장되며 다른 위치에 있습니다. 질문은 특히 연속성에 관한 것이 었습니다.
Dima

2
그러나 기존 포인터와 반복자는 무효화됩니다.
Bill Lynch

좋은 지적. 당신이 의미하는 바를 명확히하기 위해 당신의 대답에 그것을 넣어야합니다.
Dima

나에게 가장 유용한 답변
CoffeDeveloper

이제 내 프로그램이 어제 특정 요소를 제거하는 이중 루프에서 반복했을 때 왜 segfault가 발생했는지 알 수 있습니다. :) 감사합니다!
user2891462

9

실제로 표준은 a vector가 메모리에서 연속적 이며 배열을 예상하는 함수 &a[0]로 전달 될 수 있음을 보장합니다 C.

이 규칙의 예외 는 연속적인 메모리를 가지고 있지만 vector<bool>당 1 비트 만 사용 bool한다는 것입니다 bool*(이것은 잘못된 최적화와 실수로 널리 간주됩니다).

BTW, 왜 반복자를 사용하지 않습니까? 그게 그들이하는 이유입니다.


1
> BTW, 왜 반복자를 사용하지 않습니까? 그게 그들이하는 이유입니다. 어쩌면 그는 주제에 대한 Alexanrescu의 새로운 글을 읽어 : boostcon.com/site-media/var/sphene/sphwiki/attachment/2009/05/...
네마냐 Trifunovic

링크 주셔서 감사합니다. 읽기 목록으로 이동하겠습니다 (Alexandresu의 기사를 놓치지 않으려 고 노력합니다)
Motti

Mwahaha, 요즘 모두가 그 발표에 대해 이야기하는 것 같습니다. 이것에 대한 토론은 여전히 ​​뜨겁습니다 : groups.google.com/group/comp.lang.c++.moderated/browse_thread/…
Johannes Schaub-litb

주의 깊게 읽어 보면 Alexandrescu의 기사는 실제로 "C ++에서 반복기를 사용하지 마십시오"라고 말하는 것이 아니라 "Check out D"라고 말합니다. 그가 그 논문에서 설명하는 접근 방식은 기능적 유산 (List, Scheme, Haskell)을 흡수 한 기존 언어 및 프레임 워크와 놀랍도록 유사하며, 또 다른 C 기반 구문이 더 나은 서비스를위한 이상적인 출발점이되는지 진지하게 의심합니다. 목록 처리. 작년에 나는 C #과 같이 이미 확립 된 언어를 향상시키기 위해 그의 상당한 재능을 대신하도록 그를 설득하려했지만 성공이 두렵지 않다! :)
Daniel Earwicker

6

다른 사람들이 이미 말했듯이 vector내부적으로 연속적인 객체 배열을 사용합니다. 해당 배열에 대한 포인터는 상수가 아닌 멤버 함수가 IIRC라고 호출 될 때마다 유효하지 않은 것으로 처리되어야합니다.

하지만 예외가 있습니다 !!

vector<bool>공간을 절약하도록 설계된 특수 구현이 있으므로 각 부울은 1 비트 만 사용합니다. 기본 배열은 bool의 연속 배열이 아니며 배열 산술은 vector<bool>작동하지 않습니다 vector<T>.

(우리가 항상 새로운 것을 구현할 수 있기 때문에 벡터의 특수화에 대해서도 이것이 사실 일 수 있다고 생각합니다. 그러나 std::vector<bool>단순한 포인터 산술이 작동하지 않는 유일한 오류, 표준 특수화입니다.)


사용자는 전문화 할 수 없으며 std::vector다른 모든 벡터는 연속 저장소를 사용해야합니다. 따라서 std::vector<bool>(다행히도) 이상한 유일한 표준 벡터입니다. (나는이 전문화되지 않으며 예에 의해 대체되어야한다는 의견을 강하게 해요 std::dynamic_bitset거의 같은 기능을 그것은 잘못된 데이터 구조 아니에요, 그냥 벡터 아니다..)
아르네 보글

3

연속 메모리를 사용하는 벡터가 장점 인 사용 사례가 있기 때문에이 스레드를 찾았습니다.

OpenGL에서 정점 버퍼 객체를 사용하는 방법을 배우고 있습니다. 버퍼 로직을 포함하는 래퍼 클래스를 만들었으므로 버퍼를 만들기 위해 플로트 배열과 몇 가지 구성 값을 전달하기 만하면됩니다. 사용자 입력을 기반으로 함수에서 버퍼를 생성 할 수 있기를 원하므로 컴파일 시간에 길이를 알 수 없습니다. 이렇게하는 것이 가장 쉬운 해결책이 될 것입니다.

void generate(std::vector<float> v)
{
  float f = generate_next_float();
  v.push_back(f);
}

이제 벡터의 부동 소수점을 OpenGL의 버퍼 관련 함수에 배열로 전달할 수 있습니다. 이것은 또한 배열의 길이를 결정하기 위해 sizeof에 대한 필요성을 제거합니다.

이것은 플로트를 저장하기 위해 거대한 배열을 할당하고 내가 충분히 크게 만들었기를 바라는 것보다 훨씬 낫거나 연속적인 스토리지로 나만의 동적 배열을 만드는 것보다 훨씬 낫습니다.


2
이 기능은 나에게 의미가 없습니다. 자신 이 v아니라 참조 또는 포인터를 전달한다는 의미 v입니까? 전달 v만하면 함수 내부에 복사본이 만들어지고 함수가 종료 된 후에는 더 이상 존재하지 않기 때문 입니다. 따라서 함수가 끝날 때 벡터를 삭제하기 위해 벡터에 무언가를 밀어 넣습니다.
johnbakers 2013-04-05

1

cplusplus.com :

벡터 컨테이너는 동적 배열로 구현됩니다. 일반 배열과 마찬가지로 벡터 컨테이너에는 연속 된 저장 위치에 요소가 저장되어 있습니다. 즉, 반복기를 사용하는 것뿐만 아니라 요소에 대한 일반 포인터의 오프셋을 사용하여 해당 요소에 액세스 할 수 있습니다.


1

예, std :: vector의 요소는 연속적임을 보장합니다.


권리. 너무 많이 사용하는 것 같아요 :)
Benoît
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.