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


96

이후 std::liststd::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::vectorstd::list. std :: arrayc++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.