std::vector와 const & 간 문제점

ounols·2021년 10월 24일
4

std::vectorconst &형식을 함께 쓰면 몇가지 문제점이 발생하게 된다는 사실 알고 계시나요?
저도 처음 겪어봐서 몰랐는데 다시 생각해보니 벡터 자료구조 상 어쩔 수 없이 문제가 생길 수 밖에 없다고 정리가 되었습니다.

일단 한번 어떤 문제인지 알아보도록 하겠습니다.

1. 문제의 코드

std::vector<int> m_intVector = { 1, 3, 4 };
for(int i = 0; i < m_intVector.size(); ++i) {
    // 정수를 const & 형식으로 받아옵니다.
    const auto& integer = m_intVector[i];

    // 정수가 4와 같거나 더 클 때 정수를 기준으로 새로운 값을 추가합니다.
    if(integer >= 4) {
        m_intVector.push_back((int)(integer / 2));
        m_intVector.push_back(integer - 1);
    }
    // 출력
    std::cout << " [" << m_intVector[i] << "] ";
}

위 코드는 간단하게 3개의 정수가 주어지고, 4보다 크거나 같으면 그 주어진 정수를 가지고 나누거나 빼주는 간단한 코드입니다.

여기서 쉽게 유추할 수 있는 출력은 아래와 같을겁니다.

> [1]  [3]  [4]  [2]  [3] 

그러나 컴파일러가 주는 출력은 아래와 같이 다른 결과를 보여줍니다.

> [1]  [3]  [4]  [2]  [-572662308] 

2. 왜 이럴까요?

for-range문을 통해 돌리기엔 루프가 돌면서 벡터가 새로 추가되기 때문에 일반적인 for문을 사용하는 것이 더 안전한 건 알고 있습니다...

근데 왜 저런 문제가 발생할까요?


이건 벡터가 어떤 로직으로 돌아가는지 알아보면 간단합니다.
벡터는 배열의 크기를 조절할 수 없는 array의 형태에서 동적으로 크기를 조절할 수 있도록 만든 자료구조 중 하나입니다.

동적 배열 작업이 가능하지만 사실 내부를 들여다보면 일정한 배열 크기로 할당 후 할당된 크기보다 더 많은 데이터가 들어오면 배열을 기존 크기의 2+n배를 통해 더 큰 배열을 생성하고 그 곳으로 데이터를 이동합니다.

여기서 데이터가 이동한다는 것을 잘 봐야합니다. 위 코드에 선언한 integerconst auto& 형식으로 배열의 주소값을 참조하고 있습니다. 그런데 중간에 배열 크기를 새로 할당하면서 데이터를 이동시켰지만 이전 배열의 메모리는 이미 해제가 되고 난 뒤이기 때문에 integer 지역 변수는 이미 메모리 상에서 해지된 쓰레기 값을 가지고 갈 길을 잃어버립니다..ㅠㅜ

3. 해결책

std::vector<int> m_intVector = { 1, 3, 4 };
for(int i = 0; i < m_intVector.size(); ++i) {
    // 정수를 const 형식으로 받아옵니다.
    const auto integer = m_intVector[i];

    // 정수가 4와 같거나 더 클 때 정수를 기준으로 새로운 값을 추가합니다.
    if(integer >= 4) {
        m_intVector.push_back((int)(integer / 2));
        m_intVector.push_back(integer - 1);
    }
    // 출력
    std::cout << " [" << m_intVector[i] << "] ";
}

간단합니다! const auto&const auto로 바꿔서 주소값을 참조하는게 아닌 방식으로 바꿔주면 정상적으로 작동하여 아래와 같이 출력됩니다.

> [1]  [3]  [4]  [2]  [3] 

4. 쉬운 문제 같은데요?

제가 int형을 예시로 들었기 때문에 과정이나 결과값이 정말 단순합니다. 그러나 저같은 경우엔 해당 문제가 포인터 형식의 클래스를 키값으로 사용하는 벡터에서 나타났습니다.

포인터는 정말 알기 힘들었습니다. 정작 메모리 할당과 메모리 주소값은 온전하게 그대로 담겨있는데 const auto&에서만 메모리가 해제되었다는 뜻인 0xdddddddd로 떠서 알아보기 정말 힘들었습니다...

어쨌든 이렇게 혼자 삽질하다가 발견하게 되면서 아마 다른 분들도 관련해서 많이 경험하지 않을까 싶어 여기에도 이렇게 올려봅니다ㅎㅎ

profile
(게임 엔진 프로그래머가 되고싶은) 게임 클라이언트 프로그래머

0개의 댓글