2012-01-05 4 views
7

은 가정하자 나는 INT의 벡터 값의 무리로 채워집니다벡터 포인터 위치가 보장됩니까?

std::vector<int> numbers; 

, 그럼 내가 (항목 43에 존재하는)이

int *oneNumber = &numbers[43]; 

이 oneNumber 보장 할 말을 numbers.resize (46)와 같은 것으로 숫자를 크기 조정한다고해도 항상 인덱스 43의 int를 가리키고 있습니까?

예상되는 동작이 여기에 있는지 100 % 확신 할 수는 없지만 연속성이 보장되면 연속성이 보장되어 벡터의 모든 인덱스가 평생 동안 동일한 위치에 유지된다는 것을 확신 할 수 있습니다.

+0

. 그래서 저는'int * ref = & numbers [43]'과 같은 참조를 저장합니다. 나중에'push_back'을'numbers'와 WHAMMO에 넣습니다! 버그 :'ref'는 무효합니다. 왜냐하면'numbers'가 완전히 다른 메모리 공간에 완전히 할당되고 저장되기 때문입니다. – bobobobo

+0

@bobobobo 매우 사실. 생성시에 요소의 수를 알고있는 상황에서 (그리고 루핑으로 값을 생성하기 때문에'std :: array'를 사용할 수 없습니다.)'reserve'는 모든 포인터/반복자를 보장합니다 (현재 할당량을 초과하여 크기가 재조정되지 않고 포함 된 값의 주소를 이동시킬 수있는 경우) 유효합니다. 이것은 몇 차례 나를 구원해 줬지만, 계속되는 모든 시간 동안, 나는 기억할 때까지 잠시 머리를 긁어 내고 '예비'하는 것을 잊는다. : D –

답변

7

에서

는 oneNumber 항상 43

예, 이것은 표준에 의해 보장되는 인덱스에있는 INT 가리키는이 보장된다.

숫자를 numbers.resize (46)와 같이 크기를 조정한다고해도?

아니요. 벡터에 크기를 변경, 추가 또는 제거하면 벡터의 모든 주소와 반복기가 무효화됩니다. 이는 벡터가 새로운 메모리 위치로 재 할당 될 필요가 있기 때문입니다.

+0

'std :: list'를 사용하면 어떨까요? item을 추가하기 위해'list.push_back()'호출 만 사용한다면 잘못된 주소 문제를 피할 수 있을까요? (그리고 당신은'oneNumber'가 가리키는 항목을 지우지 않습니까? – bobobobo

+0

@bobobobo 그건 좋은 질문입니다. 표준이 그것에 대해 뭐라고하는지 모르겠지만'std : : list'는 모든 포인터를 무효로합니다. (제거되는 요소 제외) [우리가 참여하고 싶다면 지금 라운지에서 논의 중입니다.] (http://chat.stackoverflow.com/transcript/message/5559322 # 5559322) – Mysticial

+0

[다른 해결 방법] (http://stackoverflow.com/a/12771369/111307)에서 현재 사용하고 있습니다. – bobobobo

2

아니요 - 자랄 때 벡터를 다시 할당 할 수 있습니다. 일반적으로 벡터의 크기가 두 배가됩니다. 는 C++ 11 표준

1 Remarks: Causes reallocation if the new size is greater than the old capacity. If no 
reallocation happens, all the iterators and references before the insertion point 
remain valid. If an exception is thrown other than by the copy constructor, move 
constructor, assignment operator, or move assignment operator of T or by any 
InputIterator operation there are no effects. If an exception is thrown by the move 
constructor of a non-CopyInsertable T, the effects are unspecified. 
4

당신의 편집증은 맞습니다. std::vector의 크기를 조정하면 메모리 위치가 변경 될 수 있습니다. 즉, oneNumber은 이제 해제 된 이전 메모리 위치를 가리키고 있으므로 액세스하는 것은 정의되지 않은 동작입니다.

2

vector의 resize() 또는 reserve() 함수를 사용하여 벡터의 용량을 늘리면 어레이 지원을 위해 메모리를 다시 할당해야 할 수 있습니다. 재 할당하면 새 메모리가 같은 주소에 있지 않으므로 oneNumber에 저장된 주소가 더 이상 올바른 위치를 가리 키지 않습니다.

다시 말하지만, 이것은 벡터가 현재 저장되어있는 요소의 수와 요청 된 크기에 따라 달라집니다. 세부 사항에 따라 벡터는 재 할당하지 않고 크기를 조정할 수 있지만이 경우에 해당한다고 가정해서는 안됩니다.

4

포인터는, 참고 문헌 및 std::vector 요소에 대한 반복자는, 한 경우에만 std::vector의 크기가 시간이 포인터, 참조 자사의 capacity() 이상 성장하지 않는 std::vector에 추가로 가만히 보장됩니다 또는 반복자가 얻어졌다. capacity()을 넘어서 포인터 크기가 조정되면이 포인터에 대한 모든 참조, 이터레이터는 std::vector이 무효화됩니다. std::vector의 끝 부분 이외의 다른 부분을 삽입 할 때 상황이 무효화됩니다.

개체를 계속 배치하고 끝에 또는 처음에만 새 요소를 삽입하려면 std::deque을 사용할 수 있습니다.std::deque의 요소에 대한 포인터 및 참조는 std::deque 중간에 삽입하거나 중간에서 제거하거나 참조 된 개체를 제거 할 때만 무효화됩니다. std::deque에 요소를 삽입하거나 요소를 제거 할 때마다 std::deque에있는 요소의 반복자가 무효화됩니다.

2

벡터 용량을 변경하면 데이터가 다른 메모리 블록으로 복사되고 원본 데이터가 삭제됩니다.

3

다른 모든 사람들이 말한 것처럼 벡터에서 .resize()을 호출하면 포인터가 무효화됩니다 (이전 배열)가 완전히 할당 취소 될 수 있으며 완전히 새로운 테이블을 다시 할당하고 데이터를 복사 할 수 있습니다.

이 문제를 해결할 수있는 방법 중 하나는 입니다. STL 벡터에 포인터를 저장하지 마십시오. 대신 은 정수 인덱스을 저장합니다. 귀하의 예제에서 그래서

, 나는 항상 내가 필연적으로 벡터 내부의 객체에 대한 포인터를 필요로하기 때문에, 가치 유형의 벡터를 만드는 조심 해요 이런 이유로

std::vector<int> numbers; 
int *oneNumber = &numbers[43]; // no. pointers invalidated after .resize or possibly .push_back. 
int oneNumberIndex = 43 ;  // yes. indices remain valid through .resize/.push_back 
관련 문제