C ++에서 배열을 사용해야합니까?


96

이후 std::list및 std::vector존재처럼, C ++ 전통적인 C 배열을 사용하는 이유가있다, 또는 그들은 피해야한다 malloc?



18
@Als :이 질문은 두 개의 특정 컨테이너 간의 차이점에 관한 것이지만이 질문은 일반적으로 원시 배열과 표준 컨테이너의 차이점에 관한 것입니다.
— Jon Purdy

답변:


109

std::array사용 가능한 C ++ 11에서 대답은 "예, 배열은 피해야합니다"입니다. C ++ 11 이전에는 자동 저장소 (예 : 스택)에 배열을 할당하기 위해 C 배열을 사용해야 할 수 있습니다.


3
그러나 많은 컴파일러는 여전히 C ++ 11 지원이 부족합니다. std :: array
— Nowayz

4
std :: array는 T, N의 각 조합에 대해 템플릿이 새로 인스턴스화되기 때문에 빌드 시간 및 코드 크기 측면에서 대규모 프로젝트에 영향을 미치는 템플릿입니다.
— zvrba

std :: vector는 표준에 따른 데이터 정렬을 보장하므로 거의 모든 곳에서 사용할 수 있습니다. C ++ 11에서는 실제로 C 배열을 사용할 이유가 없습니다.
— Nils

16
@Nils 배열은 정렬도 보장합니다. 또한 자동 스토리지 할당 ( "스택")은 동적 스토리지 할당보다 훨씬 빠릅니다. 내가 정확히 3 개의 요소 (예 : 삼각형의 좌표) 가 있다는 것을 안다면 벡터를 사용할 이유가 없습니다.
— zvrba

9
@zvrba-std :: array 대 C 배열을 사용할 때 생성 된 어셈블리를 확인합니다. 전혀 차이가 없습니다.
— Nemanja Trifunovic

85

확실히, std::arrayC ++ 11에서는 실제로 정적 데이터에만 해당됩니다. C 스타일 배열에는 다음과 같은 세 가지 중요한 이점이 있습니다 std::vector.

  • 동적 할당이 필요하지 않습니다. 이러한 이유로 C 스타일 배열은 매우 작은 배열이 많을 가능성이 높은 곳에서 선호됩니다. n 차원 점과 같이 말하십시오.

    template <typename T, int dims>
    class Point
    {
        T myData[dims];
    // ...
    };

    일반적으로 dims매우 작은 (2 또는 3), T내장 유형 ( double), 그리고 std::vector<Point>수백만 개의 요소로 끝날 수 있다고 상상할 수 있습니다 . 3 배의 수백만 개의 동적 할당을 원하지는 않습니다.

  • 지원 정적 초기화입니다. 이것은 다음과 같은 정적 데이터의 문제 일뿐입니다.

    struct Data { int i; char const* s; };
    Data const ourData[] =
    {
        { 1, "one" },
        { 2, "two" },
        //  ...
    };

    이것은 모든 순서의 초기화 문제를 std::string방지 하기 때문에 벡터 (및 ) 를 사용하는 것보다 선호되는 경우가 많습니다 . 실제 코드가 실행되기 전에 데이터가 미리로드됩니다.

  • 마지막으로 위와 관련하여 컴파일러는 이니셜 라이저에서 배열의 실제 크기를 계산할 수 있습니다. 셀 필요가 없습니다.

C ++ 11에 액세스 할 수있는 경우 std::array처음 두 문제를 해결하고 첫 번째 경우에는 C 스타일 배열보다 확실히 사용해야합니다. 그러나 세 번째 문제는 다루지 않으며 이니셜 라이저 수에 따라 컴파일러 차원에서 배열을 지정하는 것이 C 스타일 배열을 선호하는 유효한 이유입니다.


11
C 스타일 배열 초기화는 또한 반복 할 필요가 없습니다. int i[] = { 1, 2, 3 };에서 계속 작업합니다 int i[] = { 1, 2, 3, 4 };. array<int, 3>수동으로으로 변경해야 array<int, 4>합니다.

10
@JoeWreschnig 쉽게 잊을 수있는 변화. 요소를 추가하면 컴파일러가 불만을 제기해야하지만 하나를 제거하면 끝에 0 초기화 요소가 추가로 남게됩니다. 나는 여전히 이런 종류의 정적 데이터에 대해 C 스타일 배열을 광범위하게 사용합니다.
— James Kanze

3
첫 번째 문장은 말이되지 않습니다.
— Konrad Rudolph

4
세 번째 포인트는 사용함으로써 오히려 품위를 해결할 수 make_array함수 와 유사하게, make_pair등등 햇 팁 @R한다. Martinho Fernandes .
— Konrad Rudolph

@KonradRudolph : 물론입니다. Andreas는 "배열을 C ++에서 사용해야합니까?"라고 묻자 James는 "확실히 std::arrayC ++ 11에서는 [그들은 정적 데이터에만 사용되어야 하지만]"라고 대답했습니다 .
— Jon Purdy

15

"절대"라고 말하지 마십시오.하지만 STL의 실제 데이터 구조로 인해 그들의 역할이 크게 줄어들 었다는 데 동의합니다.

또한 객체 내부의 캡슐화는 이와 같은 선택의 영향을 최소화해야한다고 말하고 싶습니다. 배열이 개인 데이터 멤버 인 경우 클래스의 클라이언트에 영향을주지 않고 배열을 교체 할 수 있습니다.


11

동적 메모리 할당을 사용할 수없는 안전이 중요한 시스템에서 작업했습니다. 메모리는 항상 스택에 있어야합니다. 따라서이 경우 컴파일 타임에 크기가 고정되므로 배열을 사용합니다.


8
C ++ 11 이전에는 동의했지만 std::array<T>스택에 할당하고 기본적으로 원시 배열에 오버 헤드가 없습니다.
— 111111

5
@ 111111-동의합니다. 하지만 그 업계의 일부 사람들이 아직 C ++ 11로 전환하지 않았다는 것을 알고 있습니다
— Ed Heal

그것이 내가 당신을 비하하지 않은 이유를 알고 있지만, 부스트가 버전을 가지고 있다고 생각하며 당신 자신도 쉽게 굴릴 수 있습니다.
— 111111

6
그러나 안전이 중요한 시스템에서는 새로운 컴파일러 기능 (적은 테스트)을 사용하지 않고 부스트를 사용하지 않습니다.
— James Kanze

3
많은 안전에 중요한 시스템은 새로운 컴파일러 기능이없는 OLD 컴파일러를 기반으로 구축됩니다. 도구 체인을 변경하는 것은 많은 서류 작업, 테스트 및 인증이 필요한 느리고 비용이 많이 드는 프로세스이기 때문입니다.
— Brian McFarland

6

arrayin c++은 동적 크기 std::vector및 std::list. std :: array 는 c++11. 표준 컨테이너의 이점을 제공하는 동시에 C 스타일 배열의 집계 유형 의미를 제공합니다.

그래서 c++11나는 확실히 std::array필요한 곳에서 벡터를 사용합니다. 하지만 나는 C++03.


4

대부분의 경우, 아니요 , 원시 배열을 사용하는 이유를 생각할 수 없습니다 vectors. 코드가 새 .

라이브러리가 배열 및 원시 포인터를 예상하는 코드와 호환되어야하는 경우 배열을 사용해야 할 수 있습니다.


1
...하지만 C ++ 03 이후 벡터에는 "실제로는"배열이 있으므로 포인터를 사용하여 읽기 또는 쓰기에 액세스 할 수 있습니다. 따라서 배열에 대한 포인터를 예상하는 대부분의 코드 사례를 다룹니다. 실제로 해당 코드가 벡터를 사용할 수없는 배열을 할당하거나 해제 할 때만 발생합니다.
— Steve Jessop

@SteveJessop 내부 배열에 액세스 할 수 있습니까?
— Luchian Grigore

1
@LuchianGrigore : vector.data()C ++ 11 또는 &vector.front()이전 버전.
— Mike Seymour

@Luchian : 벡터가 비어 있지 않은 경우 요소에 대한 포인터를 사용할 수 있습니다 (비어있는 경우 null 포인터와 길이 0을 제로 크기 버퍼). C ++ 03에 추가 된 벡터 연속성 보장의 유일한 목적은 포인터 지향 코드에서 벡터를 버퍼로 사용할 수 있도록하는 것입니다.
— Steve Jessop

1
@SteveJessop 그리고 많은 사람들이 어쨌든 보장된다고 생각하고 그들을 실망시키지 않는 것이 바람직하다고 생각했다는 사실.
— James Kanze

4

많은 사람들이 스택에 배열을 할당하기 위해 std :: array를, 힙에 대해 std :: vector를 지적하고 있음을 알고 있습니다. 그러나 둘 다 비 네이티브 정렬을 지원하지 않는 것 같습니다. SSE 또는 VPX 명령어를 사용하려는 모든 종류의 숫자 코드를 수행하는 경우 (따라서 각각 128 또는 256 바이트 정렬이 필요함) C 배열이 여전히 최선의 선택 인 것처럼 보입니다.


3

적은 양의 정적 데이터를 저장하는 경우 배열이 여전히 유용하다고 말하고 싶습니다.


2

std::vector내가 생각할 수있는 것 보다 배열의 유일한 장점은 (물론 필요할 때 자동으로 할당 해제를 관리하는 것으로 래핑 된) vector컴파일러가 C ++ 11 및 이동 생성자를 지원하지 않는 한 데이터의 소유권을 전달할 수 없다는 것입니다.


6
"벡터는 데이터의 소유권을 전달할 수 없습니다."-예, C ++ 03에서는 swap.
— Steve Jessop

2

C 스타일 배열은 기본적인 데이터 구조이므로 사용하는 것이 더 좋은 경우가 있습니다. 그러나 일반적인 경우에는 기본 데이터의 모서리를 둥글게 처리하는 고급 데이터 구조를 사용하십시오. C ++를 사용하면 메모리를 사용하여 매우 흥미롭고 유용한 작업을 수행 할 수 있습니다. 그 중 대부분은 단순한 배열로 작동합니다.


3
C 스타일 배열이 std::arrays 보다 더 근본적인 이유는 무엇입니까? 대부분의 경우 둘 다 동일한 어셈블리로 컴파일됩니다.
— leftaroundabout

1
더 기본적이라는 점에서 더 근본적입니다. 배열이 무엇을할지 알고 있습니다. std :: array는 표준 라이브러리에 의존하기 때문에 구현상의 문제가있을 수 있습니다.
— James Wynn

1
@JamesWynn 정말 아닙니다. std::array정적 배열 위에 구축 된 정확하게 정의 된 의미를가집니다.
— Konrad Rudolph

1

내부적으로 STL 컨테이너를 사용해야하지만 서로 다른 모듈간에 이러한 컨테이너에 대한 포인터를 전달해서는 안됩니다. 그렇지 않으면 종속성 지옥에 빠지게됩니다. 예:

std::string foo;
//  fill foo with stuff
myExternalOutputProc(foo.c_str());

아주 좋은 해결책이지만

std::string foo;
//  fill foo with stuff
myExternalOutputProc(&foo);

그 이유는 std :: string은 다양한 방법으로 구현할 수 있지만 c 스타일 문자열은 항상 c 스타일 문자열이기 때문입니다.


나는 당신이 말하려는 것이 : 표준 라이브러리의 다른 컴파일러 / 구현을 사용하여 다른 개체 코드를 함께 연결하지 마십시오. 그것은 확실히 사실입니다. 이것은 원래 질문과 어떤 관련이 있습니까?
— jogojapan

배열 또는 STL 컨테이너를 사용할 때 조언 일뿐 입니다. 컨테이너를 사용하여 데이터를 빌드하고 배열로 전달합니다. 문자열이 다른 데이터의 경우 myExternalOutputProc (foo.rawPointerGet (), foo.count ());
— user877329 2013-01-23

그러나 이러한 문제는 동일한 프로젝트에서 표준 라이브러리의 다른 구현을 결합 할 때만 발생합니다. 그건 미친 짓이야. 일반적인 코드에서 벡터를 참조로 (또는 C ++ 11에서는 이동) 함수에 전달하는 것이 좋습니다.
— jogojapan 2013 년

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