본문 바로가기
개발/C++ (98,03,11,14,17,20,23)

Modern C++ : array vs std::array (98, 11)

by snowoods 2025. 8. 10.

Modern C++

배열 : C-style array vs std::array

 

개요

C++는 C 언어에서 파생되었기 때문에 C-style 배열을 지원합니다. 하지만 C-style 배열은 포인터로의 암시적 변환(decay) 특성 때문에 크기 정보를 잃어버리기 쉽고, 경계 검사를 지원하지 않아 메모리 관련 버그를 유발할 수 있습니다. C++11부터 도입된 std::array는 이러한 단점을 보완한 현대적인 C++의 고정 크기 배열 컨테이너입니다. 이 문서에서는 두 배열 타입의 차이점과 std::array의 장점을 설명합니다.

 

C++ 버전별 주요 키워드 도입 시기

  • C++98/03: C-style 배열 사용.
  • C++11: std::array 도입.

 

내용 설명

C-style array

  • 특징:
    • 컴파일 시간에 크기가 결정되는 고정 크기 배열입니다.
    • 메모리상에 연속적으로 할당됩니다.
    • 함수에 인자로 전달될 때 배열의 이름은 배열의 첫 번째 요소를 가리키는 포인터로 변환(decay)됩니다. 이 과정에서 배열의 크기 정보가 사라집니다.
    • 크기 정보를 잃어버리기 때문에, 배열과 함께 배열의 길이를 별도의 인자로 전달해야 합니다.
    • 경계 검사(bounds checking)를 제공하지 않아, 인덱스를 벗어난 접근 시 정의되지 않은 동작(undefined behavior)을 유발할 수 있습니다.

std::array

  • 특징:
    • C-style 배열을 감싼 템플릿 클래스 컨테이너입니다. (<array> 헤더 필요)
    • 배열의 크기가 타입의 일부로 명시되므로 (std::array<T, N>), 크기 정보를 항상 유지합니다.
    • .size() 멤버 함수를 통해 언제든지 배열의 크기를 알 수 있습니다.
    • 함수에 전달할 때 포인터로 변환되지 않으며, 값이나 참조로 전체 객체를 전달할 수 있습니다.
    • [] 연산자는 경계 검사를 수행하지 않지만, .at() 멤버 함수는 경계 검사를 수행하고 범위를 벗어나면 std::out_of_range 예외를 던집니다.
    • 반복자(iterator)를 지원하여 표준 라이브러리 알고리즘과 함께 사용하기 용이합니다.

 

예제 코드

#include <array>
#include <cstdint>
#include <iostream>

// C-style array: 포인터로 디케이
void print_array_values1(const std::uint32_t *my_array, const std::uint32_t len)
{
    std::cout << "--- C-style array ---" << std::endl;
    for (std::uint32_t i = 0; i < len; i++)
    {
        std::cout << my_array[i] << "\n";
    }
}

// C++ style array: std::array
template <std::size_t N>
void print_array_values2(const std::array<std::uint32_t, N>& my_array) // 참조로 받는 것이 효율적
{
    std::cout << "--- std::array ---" << std::endl;
    for (std::size_t i = 0; i < my_array.size(); i++)
    {
        std::cout << my_array[i] << "\n";
    }
}

int main()
{
    constexpr auto len = 5U;

    // C-style array
    std::uint32_t my_array[len] = {1, 2, 3, 4, 5};
    print_array_values1(my_array, len);

    // std::array
    auto my_array2 = std::array<std::uint32_t, len>{6, 7, 8, 9, 10};
    print_array_values2(my_array2);

    return 0;
}

 

실행 결과

--- C-style array ---
1
2
3
4
5
--- std::array ---
6
7
8
9
10

 

활용팁

  • std::array를 우선 사용하세요: 현대 C++ 프로그래밍에서는 컴파일 시간에 크기를 아는 배열이 필요할 때 C-style 배열보다 std::array를 사용하는 것이 좋습니다. 타입 안정성이 높고 사용이 편리하며 실수를 줄여줍니다.
  • 함수 인자 전달: std::array를 함수에 전달할 때는 큰 배열의 경우 불필요한 복사를 피하기 위해 const 참조(const std::array<T, N>&)로 전달하는 것이 효율적입니다.
  • Range-based for loop: std::array는 반복자를 지원하므로, C-style 인덱스 기반 루프보다 범위 기반 for 루프를 사용하는 것이 더 깔끔하고 안전합니다.
    for (const auto& val : my_array2) {
        std::cout << val << "\n";
    }
  • 데이터 접근: 안전성이 중요하다면 .at()을, 성능이 중요하다면 [] 연산자를 사용하세요. 대부분의 경우 [] 연산자의 성능 저하는 미미합니다.