std :: vector :: resize () 대 std :: vector :: reserve ()


80

의 코멘트 섹션에서 스레드가 이 게시물 사용에 대한 std::vector::reserve()비교는std::vector::resize() .

다음은 원래 코드입니다.

void MyClass::my_method()
{
    my_member.reserve(n_dim);
    for(int k = 0 ; k < n_dim ; k++ )
         my_member[k] = k ;
}

에서 요소를 작성 vector하는 올바른 방법은를 호출하는 것이 std::vector::resize()아니라std::vector::reserve() .

실제로 VS2010 SP1의 디버그 빌드에서 다음 테스트 코드가 "충돌"됩니다.

#include <vector>

using namespace std;

int main()
{
    vector<int> v;
    v.reserve(10);
    v[5] = 2;

    return 0;
}

내가 맞습니까, 아니면 틀렸습니까? 그리고 VS2010 SP1이 맞습니까, 아니면 틀렸습니까?


11
설명은 "내가 잘못했다"단순하게 수 있습니다 : D
Luchian 고르

7
@LuchianGrigore은 거의 잘못 때문에 나는, "너무 지역화"로이 플래그
기본

1
:) "빨리 자신의 실수를 수정에서"로 "거의 잘못"읽기 @Default
Luchian 고르에게

1
원본 게시물의 코드가를 올바르게 사용하도록 업데이트되었으며 resize()의심이 사라졌습니다. 중재자에게 :이 질문이 "너무 현지화"된 경우 언제든지 삭제하거나 향후 다른 사람에게 도움이 될 것으로 생각되면 보관하십시오.
Mr.C64

1
이 질문은 실제로 내 프로젝트를 vc6에서 vs2013으로 마이그레이션 할 때 내 의심을 분명하게합니다. 감사합니다 :))
pengMiao

답변:


114

이유에는 두 가지 방법이 있습니다.

std::vector::reserve 메모리를 할당하지만 벡터의 크기를 조정하지 않으며 이전과 동일한 논리적 크기를 갖습니다.

std::vector::resize실제로 벡터의 크기를 수정하고 기본 상태의 객체로 모든 공간을 채 웁니다. 정수이면 모두 0이됩니다.

예약 후, 귀하의 경우에는 요소 5에 쓰기 위해 많은 push_backs가 필요합니다. 그렇게하지 않으려면 크기 조정을 사용해야합니다.

예약에 대한 한 가지 사항 : 그런 다음 push_back으로 요소를 추가하면 예약 한 용량에 도달 할 때까지 벡터의 데이터에 대한 기존 참조, 반복기 또는 포인터가 계속 유효합니다. 따라서 1000을 예약하고 크기가 5이면 &vec[4]벡터가 1000 개의 요소를 가질 때까지 동일하게 유지됩니다. 그 후에 전화를 걸면 push_back()작동하지만 &vec[4]이전에 저장된 포인터 가 더 이상 유효하지 않을 수 있습니다.


따라서 빈 벡터, 즉 vec의 경우 예약 후 vec [1]은 세그먼트 오류로 끝납니다.
hailinzeng

2
vec [1]은 정의되지 않은 동작입니다.
CashCow 2015-06-02

std::vector::reserve의 전체 배열의 가끔 복사를 방지 push_back?
Post Self

이것은 C ++ 11 또는 특정 표준 구현을위한 것입니까? []로 예약 및 액세스가있는 코드가 제대로 작동하는 것 같습니다. godbolt.org/z/MhgFdZ
Steve_Corrin

1
@Steve_Corrin 정의되지 않은 동작이 정의되지 않았습니다. 작동하는 것처럼 보일 수 있습니다. 여전히 잘못된 코드입니다. < size()컨테이너 내에 존재하지 않는 요소에 대한 인덱싱은 허용되지 않습니다. 그들은 언어의 정의에 따라 거기에 존재하지 않습니다. 컴파일러가 핵을 시작하지 않기로 결정하고 대신 원하는 방식으로 RAM을 찌르거나 엿 본다면 그것은 행운입니다. 아니면 불운이 아닐까요? 이상적으로 우리는 모든 프로그래머가 할 수있는 모든 잘못된 것들을 잡을 수 있지만, 좋은 행운은 지금까지이 점점!
underscore_d

25

Jan Hudec의 답변 : vector :: resize () 및 vector :: reserve () 중에서 선택

두 기능은 매우 다른 일을합니다.

resize () 메서드 (그리고 생성자에 인수를 전달하는 것은 그와 동일)는 주어진 수의 요소를 벡터에 삽입합니다 (값을 지정하는 선택적 두 번째 인수가 있음). 그것은 size ()에 영향을 미칠 것이고, 반복은 그 모든 요소를 ​​지나갈 것이고, push_back은 그것들 뒤에 삽입 될 것이고, operator []를 사용하여 직접 접근 할 수 있습니다.

reserve () 메서드는 메모리 만 할당하지만 초기화되지 않은 상태로 둡니다. capacity ()에만 영향을 주지만 size ()는 변경되지 않습니다. 벡터에 아무것도 추가되지 않기 때문에 객체에 대한 값이 없습니다. 그런 다음 요소를 삽입하면 사전에 수행되었으므로 재 할당이 발생하지 않지만 그게 유일한 효과입니다.

그래서 그것은 당신이 원하는 것에 달려 있습니다. 1000 개의 기본 항목 배열을 원하면 resize ()를 사용하십시오. 1000 개의 항목을 삽입 할 것으로 예상하고 몇 가지 할당을 피하려면 reserve ()를 사용하십시오.

편집 : Blastfurnace의 의견은 질문을 다시 읽고 귀하의 경우 정답이 수동으로 사전 할당되지 않는다는 것을 깨달았습니다. 필요에 따라 끝에 요소를 계속 삽입하십시오. 벡터는 필요에 따라 자동으로 재 할당되며 언급 된 수동 방식보다 더 효율적입니다. reserve ()가 의미있는 유일한 경우는 사전에 쉽게 사용할 수 있어야하는 총 크기를 합리적으로 정확하게 추정 한 경우입니다.

EDIT2 : 광고 질문 편집 : 초기 추정치가있는 경우 해당 추정치보다 reserve ()하고 충분하지 않은 것으로 판명되면 벡터가 그 일을하도록하십시오.


12

무엇을하고 싶은지에 따라 다릅니다. reserve에 요소를 추가 하지 않습니다vector . 을 변경하기 만하면 요소 추가 가 재 할당되지 않도록 capacity()보장합니다 (예 : 반복기 무효화). 즉시 요소를 추가합니다. 나중에 요소를 추가하려면 ( , )을 사용하십시오 . 나중에 요소에 액세스하려면 ( 또는 사용 )을 사용하십시오 . 따라서 다음 중 하나가 될 수 있습니다.resizeinsert()push_back()reserve[]at()resizeMyClass::my_method

void MyClass::my_method()
{
    my_member.clear();
    my_member.reserve( n_dim );
    for ( int k = 0; k < n_dim; ++ k ) {
        my_member.push_back( k );
    }
}

또는

void MyClass::my_method()
{
    my_member.resize( n_dim );
    for ( int k = 0; k < n_dim; ++ k ) {
        my_member[k] = k;
    }
}

당신이 선택한 것은 취향의 문제이지만, 당신이 인용 한 코드는 분명히 틀 렸습니다.


3

벡터의 현재 크기보다 작은 숫자로 두 메서드가 호출되는 경우에 대한 논의가있을 것입니다.

부름 reserve()용량보다 작은 번호로 를 용량이나 용량에 영향을주지 않습니다.

부름 resize()현재 크기보다 작은 숫자로 하면 컨테이너가 해당 크기로 축소되어 초과 요소를 효과적으로 제거합니다.

요약 resize()하면 메모리가 확보되지만 reserve()그렇지 않습니다.


크기 조정 은 메모리를 해제 하지 않습니다 . 크기가 작아지면 소멸자가 호출되지만 메모리는 유지됩니다 (용량은 변경되지 않음).
John Gordon

2

예, 맞습니다. Luchian은 방금 오타를 작성했으며 아마도 그의 실수를 깨닫기에는 커피가 부족한 것 같습니다.


1

크기 조정은 실제로 벡터의 요소 양을 변경하고 크기 조정으로 인해 벡터가 커지면 새 항목이 기본적으로 구성됩니다.

vector<int> v;
v.resize(10);
auto size = v.size();

이 경우 크기는 10입니다.

반면에 reserve는 내부 버퍼가 지정된 크기로 증가하도록 요청하지만 배열의 "크기"를 변경하지 않고 버퍼 크기 만 변경합니다.

vector<int> v;
v.reserve(10);
auto size = v.size();

이 경우 크기는 여전히 0입니다.

따라서 귀하의 질문에 대답하려면 예, 맞습니다. 충분한 공간을 예약하더라도 인덱스 연산자로 초기화되지 않은 메모리에 액세스하고 있습니다. int를 사용하면 그렇게 나쁘지는 않지만 클래스 벡터의 경우 생성되지 않은 객체에 액세스하게됩니다.

디버그 모드로 설정된 컴파일러의 경계 검사는이 동작으로 인해 혼란 스러울 수 있으며, 이것이 충돌이 발생하는 이유 일 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.