Array declaration
배열 타입의 객체를 선언합니다.
목차구문배열 선언은 선언자가 다음 형식을 가지는 모든 단순 선언입니다.
목록
배열은 모든 기본 타입(
참조의 배열이나 함수의 배열은 존재하지 않습니다. 배열 타입에 cv-한정자를 적용하면(typedef 또는 템플릿 타입 조작을 통해) 요소 타입에 한정자가 적용되지만, 요소가 cv-한정된 타입인 배열 타입은 동일한 cv-한정을 가진 것으로 간주됩니다. // a and b have the same const-qualified type "array of 5 const char"
typedef const char CC;
CC a[5] = {};
typedef char CA[5];
const CA b = {};
new[]-표현식과 함께 사용될 때 배열의 크기는 0일 수 있습니다; 이러한 배열은 요소가 없습니다: int* p = new int[0]; // accessing p[0] or *p is undefined
delete[] p; // cleanup still required
실제로는 표현의 간결함을 위해 배열 요소에 대한 포인터를 배열에 대한 포인터라고 부르기도 합니다: int arr[5] {};
int *p = arr;
할당배열 타입의 객체는 전체적으로 수정될 수 없습니다: 비록 그것들이 lvalues (예: 배열의 주소를 취할 수 있음)일지라도, 대입 연산자의 좌변에 나타날 수 없습니다: int a[3] = {1, 2, 3}, b[3] = {4, 5, 6}; int (*p)[3] = &a; // 정상: a의 주소를 취할 수 있음 a = b; // 오류: a는 배열임 struct { int c[3]; } s1, s2 = {3, 4, 5}; s1 = s2; // 정상: 암시적으로 정의된 복사 할당 연산자가 // 배열 타입의 데이터 멤버를 할당할 수 있음 배열-포인터 변환배열 타입의 좌측값과 우측값에서 포인터 타입의 우측값으로 암시적 변환 이 존재합니다: 이는 배열의 첫 번째 요소를 가리키는 포인터를 생성합니다. 이 변환은 배열이 예상되지 않지만 포인터가 예상되는 컨텍스트에서 배열이 나타날 때마다 사용됩니다:
이 코드 실행
#include <iostream> #include <iterator> #include <numeric> void g(int (&a)[3]) { std::cout << a[0] << '\n'; } void f(int* p) { std::cout << *p << '\n'; } int main() { int a[3] = {1, 2, 3}; int* p = a; std::cout << sizeof a << '\n' // 배열의 크기를 출력 << sizeof p << '\n'; // 포인터의 크기를 출력 // 배열은 허용되지만 포인터는 허용되지 않는 경우, 배열만 사용 가능 g(a); // 정상: 함수가 참조로 배열을 받음 // g(p); // 오류 for (int n : a) // 정상: 범위 기반 for 루프에서 배열 사용 가능 std::cout << n << ' '; // 배열의 요소들을 출력 // for (int n : p) // 오류 // std::cout << n << ' '; std::iota(std::begin(a), std::end(a), 7); // 정상: begin과 end는 배열을 받음 // std::iota(std::begin(p), std::end(p), 7); // 오류 // 포인터는 허용되지만 배열은 허용되지 않는 경우, 둘 다 사용 가능: f(a); // 정상: 함수가 포인터를 받음 f(p); // 정상: 함수가 포인터를 받음 std::cout << *a << '\n' // 첫 번째 요소 출력 << *p << '\n' // 동일 << *(a + 1) << ' ' << a[1] << '\n' // 두 번째 요소 출력 << *(p + 1) << ' ' << p[1] << '\n'; // 동일 } 다차원 배열배열의 원소 타입이 다른 배열일 때, 그 배열을 다차원 배열이라고 합니다: // 2개의 배열로 이루어진 배열, 각 배열은 3개의 int를 가짐 int a[2][3] = {{1, 2, 3}, // 2 × 3 행렬로 볼 수 있음 {4, 5, 6}}; // 행 우선 배치 방식 배열-포인터 변환(decay)이 적용될 때, 다차원 배열은 첫 번째 요소(예: 첫 번째 행이나 첫 번째 평면)에 대한 포인터로 변환된다는 점에 유의하십시오: 배열-포인터 변환은 한 번만 적용됩니다. int a[2]; // 2개의 int를 가지는 배열 int* p1 = a; // a는 a의 첫 번째 요소를 가리키는 포인터로 decay됨 int b[2][3]; // 3개의 int를 가지는 2개의 배열의 배열 // int** p2 = b; // 오류: b는 int**로 decay되지 않음 int (*p2)[3] = b; // b는 b의 첫 번째 3-요소 행을 가리키는 포인터로 decay됨 int c[2][3][4]; // 4개의 int를 가지는 3개의 배열의 2개의 배열의 배열 // int*** p3 = c; // 오류: c는 int***로 decay되지 않음 int (*p3)[3][4] = c; // c는 c의 첫 번째 3 × 4-요소 평면을 가리키는 포인터로 decay됨 경계를 알 수 없는 배열만약 expr 이 배열 선언에서 생략되면, 선언된 타입은 "T의 알려지지 않은 경계의 배열"이며, 이는 일종의 불완전 타입 입니다. 단, 집합체 초기화 와 함께 사용되는 선언에서는 예외입니다: extern int x[]; // x의 타입은 "크기를 알 수 없는 int 배열"입니다 int a[] = {1, 2, 3}; // a의 타입은 "3개의 int 배열"입니다 배열 요소가 알려지지 않은 경계의 배열일 수 없기 때문에, 다차원 배열은 첫 번째 차원을 제외한 다른 차원에서 알려지지 않은 경계를 가질 수 없습니다: extern int a[][2]; // 정상: 알 수 없는 경계를 가진 2개 int 배열의 배열 extern int b[2][]; // 오류: 배열이 불완전한 요소 타입을 가짐 동일한 범위 내에서 해당 개체의 선행 선언이 있고 그 범위에서 경계가 지정된 경우, 생략된 배열 경계는 이전 선언에서와 동일하게 간주되며, 이는 클래스의 정적 데이터 멤버 정의에도 유사하게 적용됩니다: extern int x[10]; struct S { static int y[10]; }; int x[]; // OK: 경계는 10 int S::y[]; // OK: 경계는 10 void f() { extern int x[]; int i = sizeof(x); // 오류: 불완전한 객체 타입 } 알려지지 않은 경계를 가진 배열에 대한 참조자와 포인터는 형성될 수 있으나, 초기화하거나 할당할 수 없습니다 (C++20 이전) 초기화하거나 할당할 수 있습니다 (C++20 이후) 알려진 경계를 가진 배열 및 배열 포인터로부터. C 프로그래밍 언어에서는 알려지지 않은 경계를 가진 배열에 대한 포인터가 알려진 경계를 가진 배열에 대한 포인터와 호환되므로, 양방향으로 변환 및 할당이 가능합니다. extern int a1[]; int (&r1)[] = a1; // 정상 int (*p1)[] = &a1; // 정상 int (*q)[2] = &a1; // 오류 (C에서는 정상) int a2[] = {1, 2, 3}; int (&r2)[] = a2; // 정상 (C++20부터) int (*p2)[] = &a2; // 정상 (C++20부터) 알 수 없는 경계를 가진 배열에 대한 포인터는 포인터 산술 에 참여할 수 없으며 첨자 연산자 의 왼쪽에 사용될 수 없지만, 역참조는 가능합니다. 배열 rvalues배열은 함수에서 값으로 반환될 수 없으며 대부분의 캐스트 표현식의 대상이 될 수 없지만, 배열 prvalue 는 타입 별칭을 사용하여 brace-initialized functional cast 를 통해 배열 임시 객체를 구성함으로써 형성될 수 있습니다.
배열 xvalue 는 클래스 rvalue의 배열 멤버에 직접 접근하거나 std::move 를 사용하거나 rvalue 참조를 반환하는 다른 캐스트나 함수 호출을 통해 직접 형성될 수 있습니다.
이 코드 실행
#include <iostream> #include <type_traits> #include <utility> void f(int (&&x)[2][3]) { std::cout << sizeof x << '\n'; } struct X { int i[2][3]; } x; template<typename T> using identity = T; int main() { std::cout << sizeof X().i << '\n'; // 배열의 크기 f(X().i); // 정상: xvalue에 바인딩 // f(x.i); // 오류: lvalue에 바인딩할 수 없음 int a[2][3]; f(std::move(a)); // 정상: xvalue에 바인딩 using arr_t = int[2][3]; f(arr_t{}); // 정상: prvalue에 바인딩 f(identity<int[][3]>{{1, 2, 3}, {4, 5, 6}}); // 정상: prvalue에 바인딩 } 출력: 24 24 24 24 24 결함 보고서다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.
참고 항목
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||