이제 std :: array가 생겼으니 C 스타일 배열의 용도는 무엇입니까?


답변:


60

내가 놓친 것이 아니라면 (최근의 표준 변경 사항을 너무 가깝게 따르지 않았 음) 대부분의 C 스타일 배열 사용은 여전히 ​​남아 있습니다. std::array정적 초기화를 허용하지만 여전히 이니셜 라이저를 계산하지 않습니다. 그리고 이전에 C 스타일 배열의 유일한 실제 사용은 std::array다음 행을 따라 정적으로 초기화 된 테이블에 대한 것이기 때문 입니다.

MyStruct const table[] =
{
    { something1, otherthing1 },
    //  ...
};

일반 beginend템플릿 함수 (C ++ 11에서 채택)를 사용하여 반복합니다. 컴파일러가 이니셜 라이저 수에서 결정하는 크기는 언급하지 않습니다.

편집 : 내가 잊은 또 다른 점 : 문자열 리터럴은 여전히 ​​C 스타일 배열입니다. 즉 유형 char[]. 나는 우리가 std::array.


7
길이를 지정하지 않고도 배열을 구성하는 가변 함수 템플릿을 작성할 수 있습니다.
rightfold apr

2
C ++ 17 클래스 템플릿 추론을 통해 이니셜 라이저 수의 자동 추론이 지원됩니다. 예 : "auto a = std :: array {1, 2, 3};"
Ricky65

Nitpick는 : 문자열 리터럴의 유형입니다const char[]
Bulletmagnet

30

아뇨 .. 솔직히 말 해서요 그리고 30 자입니다.

물론을 구현하려면 C 배열이 필요 std::array하지만 이것이 실제로 사용자가 C 배열을 원하는 이유는 아닙니다. 또한, 아니, std::arrayC 배열보다 확대됨에없는, 그리고 경계 - 검사 액세스를위한 옵션이 있습니다. 마지막으로 모든 C ++ 프로그램이 표준 라이브러리에 의존하는 것은 완전히 합리적입니다. 즉, 표준 라이브러리에 대한 액세스 권한이없는 경우 컴파일러는 표준 라이브러리를 따르지 않습니다. 질문은 "C ++"가 아니라 "C ++"로 태그가 지정되어 있으며, 부적절하다고 느꼈기 때문에 사양의 절반을 놓친 C ++가 아닌 것입니다.


1
흠. 다른 언어에서 호출되고 매개 변수로 전달해야하는 C ++ 코드를 작성하는 경우 어떻게해야합니까?
asveikau

3
독립 구현은 거의 모든 표준 라이브러리를 생략하고 여전히 준수 할 수 있습니다. 그래도 std::array독립형 C ++ 11 구현에서는 구현할 수없는 컴파일러에 대해 심각한 의구심을 가질 것 입니다.
Dennis Zickefoose

11
C ++ 0x 최종 초안 (문서 N3092) § 1.4.7 "호스팅 된 구현과 독립형의 두 가지 구현이 정의되어 있습니다. 호스팅 된 구현의 경우이 국제 표준은 사용 가능한 라이브러리 세트를 정의합니다. 독립 구현은 운영 체제의 이점없이 발생하며 특정 언어 지원 라이브러리를 포함하는 구현 정의 라이브러리 세트가 있습니다. ".. STL은 독립 컴파일러에서"언어 지원 "라이브러리로 포함되지 않습니다
Earlz

24

다차원 배열을 사용하는 것이 C 배열보다 std::array. 예를 들어

char c_arr[5][6][7];

반대로

std::array<std::array<std::array<char, 7>, 6>, 5> cpp_arr;

또한 C 배열의 자동 감쇠 속성으로 인해 c_arr[i]위의 예에서 포인터로 감쇠하고 나머지 차원을 두 개의 추가 매개 변수로 전달하면됩니다. 내 요점은 c_arr복사하는 데 비싸지 않다는 것 입니다. 그러나 cpp_arr[i]복사하는 데 비용이 많이 듭니다.


1
그러나 array차원을 잃지 않고 다차원 을 함수에 전달할 수 있습니다. 그리고 그것을 함수 템플릿에 전달하면 그 함수는 각 차원의 차원과 크기를 모두 추론하거나 둘 중 하나만 추론 할 수 있습니다. 이것은 주로 임의의 차원에서 작동하는 과학적 템플릿 라이브러리에 흥미로울 수 있습니다.
Sebastian Mach

29
간단한 template <typename T, int M, int N> using array2d = std::array<std::array<T, N>, M>;것은 이러한 문제를 해결해야합니다.
Miles Rout 2013 년

6
귀하의 예 c_arr는 복사하는 데 매우 비쌉니다! 그렇게하려면 코드를 직접 제공해야합니다. 감쇠되는 포인터는 복사본보다 참조에 더 가깝고 std::array원하는 경우 참조를 전달하는 데 사용할 수 있습니다 .
ChetS

1
@MilesRout 기술적으로 , std::size_t대신 해야하지 int않습니까? nitpicking 미안하지만 이것은 보편적으로 만들 것입니다.
robbie

1
@ robbie0630 예 size_t, 원하는 경우 만들 수 있습니다 .하지만 40 억 개 이상의 행 또는 열이있는 배열이 필요한 시나리오가 많다는 것은 상상할 수 없습니다.
Miles Rout

13

Sumant가 말했듯이 다차원 배열은 std::array.

중첩되면 std::array읽기가 매우 어려워지고 불필요하게 장황해질 수 있습니다.

예를 들면 :

std::array<std::array<int, 3>, 3> arr1; 

에 비해

char c_arr[3][3]; 

또한, 참고 begin(), end()size()모든 반환 의미 값을 때 둥지 std::array.

이러한 이유로 고정 크기의 다차원 배열 컨테이너 array_2darray_3d. 그들은 유사합니다std::array 하지만 2 차원 및 3 차원의 다차원 배열에 사용됩니다. 내장 된 다차원 배열보다 안전하고 성능이 나쁘지 않습니다. 흔하지 않기 때문에 차원이 3보다 큰 다차원 배열에 대한 컨테이너를 포함하지 않았습니다. C ++ 0x에서는 임의의 차원 수를 지원하는 가변 템플릿 버전을 만들 수 있습니다.

2 차원 변형의 예 :

//Create an array 3 x 5 (Notice the extra pair of braces) 

fsma::array_2d <double, 3, 5> my2darr = {{
    { 32.19, 47.29, 31.99, 19.11, 11.19},
    { 11.29, 22.49, 33.47, 17.29, 5.01 },
    { 41.97, 22.09, 9.76, 22.55, 6.22 }
}};

전체 문서는 여기에서 볼 수 있습니다.

http://fsma.googlecode.com/files/fsma.html

여기에서 라이브러리를 다운로드 할 수 있습니다.

http://fsma.googlecode.com/files/fsma.zip


4
고정 크기 C 스타일 배열은 쉽지만 차원을 변경하려면 상황이 복잡해집니다. 예를 들어, 주어진 경우 배열의 배열, 포인터 배열, 배열에 대한 포인터 또는 포인터에 대한 포인터 arr[x][y]인지 알 수 없습니다 arr. 구현을위한 모든 것은 필요에 따라 합법적입니다. 그리고 아마도 다차원 배열에 대한 대부분의 실제 사용 사례에서는 런타임에 크기를 결정해야합니다.
Keith Thompson

n 차원 배열의 가변 템플릿 구현을보고 싶습니다! 최상의 메타 프로그래밍!
steffen 2014-10-22

3
@steffen 몇 년 전에 시도했습니다. 당신은 여기에서 볼 수 있습니다 code.google.com/p/fsma/source/browse/trunk/...를 . 여기에 테스트 케이스 : code.google.com/p/fsma/source/browse/trunk/... . 그래도 훨씬 더 잘 할 수 있다고 확신합니다.
Ricky65 2014

5

C ++에서 사용할 수있는 C 스타일 배열은 실제로 실제 C 배열보다 훨씬 덜 다재다능합니다. 차이점은 C에서는 배열 유형이 런타임 크기를 가질 수 있다는 것 입니다. 다음은 유효한 C 코드이지만 C ++ C 스타일 배열이나 C ++ array<>유형 으로 표현할 수 없습니다 .

void foo(int bar) {
    double tempArray[bar];
    //Do something with the bar elements in tempArray.
}

C ++에서는 힙에 임시 배열을 할당해야합니다.

void foo(int bar) {
    double* tempArray = new double[bar];
    //Do something with the bar elements behind tempArray.
    delete[] tempArray;
}

이는 컴파일 타임에 알려지지 std::array<>않았기 때문에 으로 달성 할 수 없습니다 . barC ++ 또는의 C 스타일 배열을 사용해야합니다 std::vector<>.


첫 번째 예는 비교적 용이 (요구되는 이나마 ++ C로 표현 될 수 있지만 new[]하고 delete[], 다음은 C ++없이 달성 될 수있다) std::vector<>:

void smoothImage(int width, int height, int (*pixels)[width]) {
    int (*copy)[width] = malloc(height*sizeof(*copy));
    memcpy(copy, pixels, height*sizeof(*copy));
    for(y = height; y--; ) {
        for(x = width; x--; ) {
            pixels[y][x] = //compute smoothed value based on data around copy[y][x]
        }
    }
    free(copy);
}

요점은 라인 배열에 대한 포인터가 int (*)[width]C ++에서 런타임 너비를 사용할 수 없다는 것입니다. 이로 인해 C ++에서 C에서보다 이미지 조작 코드가 훨씬 더 복잡해집니다. 이미지 조작 예제의 일반적인 C ++ 구현은 다음과 같습니다.

void smoothImage(int width, int height, int* pixels) {
    int* copy = new int[height*width];
    memcpy(copy, pixels, height*width*sizeof(*copy));
    for(y = height; y--; ) {
        for(x = width; x--; ) {
            pixels[y*width + x] = //compute smoothed value based on data around copy[y*width + x]
        }
    }
    delete[] copy;
}

이 코드는 위의 C 코드와 정확히 동일한 계산을 수행하지만 인덱스가 사용되는 모든 곳에서 수동으로 인덱스 계산을 수행해야합니다 . 2D의 경우 여전히 가능합니다 (지수 계산을 잘못 할 수있는 많은 기회가 있음에도 불구하고). 하지만 3D 케이스에서는 정말 불쾌 해집니다.

저는 C ++로 코드를 작성하는 것을 좋아합니다. 하지만 다차원 데이터를 조작해야 할 때마다 코드의 해당 부분을 C로 옮겨야하는지 스스로에게 물어 봅니다.


7
최소한 Clang 및 GCC는 C ++에서 VLA를 지원합니다.
Janus Troelsen 2014-06-06

@JanusTroelsen 및 지원하는 요소 유형이 끔찍하게 제한되어 있습니다.
rightfold apr

C11은 VLA를 선택 사항으로 만들지 않습니까? 그렇다면 귀하의 답변이 오해의 소지가 있다고 생각합니다. C99가 표준이지만 C11이 아닌 경우 정확합니다.
Z boson

1
@Zboson C99는 C 표준이며 VLA 기능 ( gcc예 :)을 구현하는 컴파일러가 있습니다. C11은 꽤 흥미로운 것들을 선택적으로 만들었고, 그들이 그 기능을 금지하기를 원하기 때문이라고 생각하지 않습니다. 나는 그것을 완전히 표준 호환 컴파일러를 작성하기 위해 레벨을 낮추고 싶다는 신호로 보는 경향이 있습니다 .VLA는 구현하기가 매우 어려운 짐승이며 많은 코드가 없이도 할 수 있으므로 새로운 컴파일러가 새로운 컴파일러에 적합합니다. VLA를 즉시 구현할 필요가 없습니다.
cmaster-monica reinstate monica

-1

std::array느리지 않을 수 있습니다 . 그러나 간단한 저장소를 사용하여 벤치마킹을 수행하고 std :: array에서 읽었습니다. 아래 벤치 마크 결과를 참조하십시오 (W8.1, VS2013 업데이트 4).

ARR_SIZE: 100 * 1000
Avrg = Tick / ARR_SIZE;

test_arr_without_init
==>VMem: 5.15Mb
==>PMem: 8.94Mb
==>Tick: 3132
==>Avrg: 0.03132
test_arr_with_init_array_at
==>VMem: 5.16Mb
==>PMem: 8.98Mb
==>Tick: 925
==>Avrg: 0.00925
test_arr_with_array_at
==>VMem: 5.16Mb
==>PMem: 8.97Mb
==>Tick: 769
==>Avrg: 0.00769
test_c_arr_without_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 358
==>Avrg: 0.00358
test_c_arr_with_init
==>VMem: 5.16Mb
==>PMem: 8.94Mb
==>Tick: 305
==>Avrg: 0.00305

네거티브 마크에 따르면 내가 사용한 코드는 pastebin ( link )에 있습니다.

벤치 마크 클래스 코드는 여기에 있습니다 .

벤치마킹에 대해 잘 모르겠습니다 ... 내 코드에 결함이있을 수 있습니다.


6
벤치 마크 코드 또는 컴파일 플래그없이 결과를 벤치 마크합니까? 어서, 당신은 더 잘할 수 있습니다.
R. Martinho Fernandes

FWIW, 아주 작은 코드 만 이미 벤치 마크에 심각한 결함이 있음을 보여줍니다. 스마트 충분히 컴파일러 단지로 전체를 켜집니다long test_arr_without_init() { return ARR_SIZE; }
R. 마르틴 페르난데스

그것은 단지 예일뿐입니다. 큰 문제가 아니라고 생각했습니다. / O2 / Ot / Gl과 함께 VS 2013에서 릴리스 빌드를 사용하여 void를 반환하도록 코드를 변경했습니다.
K'Prime 2015

반환 값을 제거하면 컴파일러가 모든 것을 void test_arr_without_init() {}지금 으로 바꿀 수 있습니다 . 측정하려는 코드가 측정하려는 코드인지 확인하기 위해 작업을 진행해야합니다.
R. Martinho Fernandes

-6
  1. 같은 것을 구현하기 위해 std::array
  2. STL을 사용하지 않거나 사용할 수없는 경우
  3. 성능을 위해

27
std::arrayC 어레이보다 성능이 떨어지는 방법 을 알려주십시오 .
Xeo

2
wikipedia에서 : "배열 구현은 바운드 검사를 수행 할 필요가 없습니다. 그러나 boost의 구현은 operator []에 대해 수행하지만 반복자는 수행하지 않습니다." -그래서 operator []는 더 느립니다. 구현을 살펴 보지 않았지만 구현의 모든 코드가 최적화 프로그램을 방해 할 수 있습니다.
Lou Franco

19
@Aaron McDaid : 그것은 단지에서입니다 at(), 그것은에없는 operator[]것처럼 std::vector. 성능 저 하나 코드 부풀림이 없으며 std::array컴파일러는 이러한 종류의 최적화를 위해 설계되었습니다. 물론 체크 된 기능의 추가는 훌륭한 디버그 도구이자 큰 장점입니다. @Lou Franco : 모든 C ++ 코드는 표준 라이브러리에 의존 할 수 있습니다. @Earlz : STL을 사용할 수 없다면 C ++가 아닙니다. 그게 끝입니다.
Puppy

6
@Earlz : C ++ 표준에는 표준 라이브러리가 포함되어 있습니다. 라이브러리를 사용할 수 없다면 적합하지 않은 것입니다. 그리고 두 번째로, std::array동등한 C 배열 사용보다 더 많이 사용하려면 엉뚱한 컴파일러 가 있어야합니다.
Puppy

5
@Earlz : "순응하지 않음"과 "사양에 수백 페이지가있는 누락 된 기능"사이에는 큰 차이가 있습니다.
Puppy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.