2012-12-04 3 views
6

의 내용에 배열 참조 'T (&) [n]`을 가져온다. std::array<T, n>이 있고 그 내용에 대한 배열 참조를 원한다고 가정한다. elems 배열 구성원).`std :: array <T, n>`

나는 std::array<T, n>::data()T *이 아니라 T (&)[n]이 아니기 때문에 어떤 종류의 캐스트가 필요하다고 생각하여 놀랐다. 쓸 수 있습니다 :

std::array<int, 5> arr; 
int (&ref)[5] = *reinterpret_cast<int (*)[5]>(arr.data()); 

그러나 이것은보기 흉하고 잠재적으로 안전하지 않습니다. 합법적 인 (잘 정의 된) 코드인가요? 더 좋은 방법이 있습니까?

+0

재사용 가능한'constexpr' 함수 템플릿을 제안하여 그 추악함을 숨길 수 있습니다. –

+0

코너 케이스는 크기가 0 일 때 오른쪽 경우는 정의되지 않은 동작이지만 왼쪽 측면도 컴파일되지 않습니다 (예 : 0 요소의 배열을 선언 할 수 없음) –

+0

'5'보다는'arr.size()'를 사용하는 것이 덜 부서지기 쉽습니다 ('constexpr'이므로 배열 크기로 사용할 수 있습니다). 하지만 캐스트가 잘 정의되어 있는지 여부는 확실하지 않습니다. –

답변

3

표준은 array의 기본이되는 구현을 제공하지 않지만, 경우에만 캐스트 (비 이식) 법적 될 것이라고 구현 한 후, 기본 표현으로 int[5]을 사용합니다. 다른 기본 표현의 경우 엄격한 앨리어싱 규칙을 위반하고 정의되지 않은 동작을 입력합니다.

배열을 배열로 반환하는 대신, 표준 라이브러리의 선례에 따라 관심있는 범위를 구분하는 반복자 쌍을 사용할 수 있습니까?

+0

요소는 연속적으로 저장되므로 (23.3.2.1p1) 어쨌든 배열로 별명을 지정할 수 없습니까? – ecatmur

+0

@ecatmur'array'에있는 원래의 기본 타입이 타입을 캐스팅 한 경우에만 - 그렇지 않으면 원래 타입을 잘못 앨리어싱하여 정의되지 않은 동작입니다. 공간을'aligned_storage' 또는 실제 배열이 아닌 다른 것으로 구현하기로 결정한 컴파일러를 생각해보십시오. –

+0

@MarkB : 그러나'data()'멤버는 데이터에 대한 액세스를 일반 배열과 동일한 메모리 레이아웃을 갖는 * dynamic * 배열로 제공해야합니다. 나는이 (거의 끔찍한) 캐스트를하는 것이 거의 항상 안전하다고 말하고 싶다. 나는. 'data()'는 이미 * 배열 호환 가능 * 방식으로 내부 표현의 별명을 지정했습니다. –

0

C++의 배열은 결함 유형입니다 (여기서는이 아닌 C 스타일 배열에 대해 이야기하고 있습니다). 그 이유는 배열의 크기가 메모리의 어느 위치에도 저장되지 않기 때문에 컴파일시에만 알 수 있기 때문입니다. 배열을 다른 유형 (일반적으로 포인터)으로 변환하면 배열의 크기가 손실됩니다.

이제 역방향 캐스트를 수행 할 수 없다는 것을 알 수 있습니다. 컴파일러가 첫 번째 멤버에 대한 포인터 만보고 배열의 크기를 알 수있는 방법이 없기 때문입니다. 이미 제안 된 것처럼 반복자 쌍을 사용할 수 있습니다.

관련 문제