C ++ 참조로 배열 전달


78

참조로 배열을 전달할 수 있습니까?

 void foo(double& *bar) 

내 컴파일러가 아니오라고 말하는 것 같습니다. 왜? 참조로 배열을 전달하는 올바른 방법은 무엇입니까? 아니면 해결 방법? 내 메서드가 수정해야하고 나중에 검색해야하는 배열 인수가 있습니다. 또는이 배열을 잘 작동하는 클래스 멤버로 만들 수 있지만 코드의 다른 부분에는 많은 단점이 있습니다 (피하고 싶습니다).

감사합니다.



1
을 (를) 사용하는 것을 고려해 std::vector보셨습니까?
moooeeeep

1
@moooeeeep std::vector는 크기가 동적 / 알 수없는 경우 분명히 우월하지만 크기가 항상 같은 경우 과잉 일 것이며 대신 std::array구문 적 추악함을 해결하는 동시에 값 의미를 부여합니다.
underscore_d


왜 그냥 void foo (double bar [])? 원한다면, array의 길이를 void foo (double bar [2])로 지정할 수도 있습니다. 복잡한 유형의 경우가 아니면 복사 생성자를 피해야합니다.
최종 원인

답변:


136

배열은 실제로 참조로만 전달할 수 있습니다.

void foo(double (&bar)[10])
{
}

이렇게하면 다음과 같은 작업을 할 수 없습니다.

double arr[20];
foo(arr); // won't compile

임의의 크기 배열을에 전달할 수 있으려면이를 foo템플릿으로 만들고 컴파일 타임에 배열의 크기를 캡처합니다.

template<typename T, size_t N>
void foo(T (&bar)[N])
{
    // use N here
}

당신은 심각하게 사용하는 것이 좋습니다 std::vector, 또는 컴파일러가 지원하는 C ++ (11)이있는 경우 std::array.


7
"그래도 일단에 전달 foo되면 배열은 포인터로 붕괴됩니다." 그렇지 않습니다. 10 개 요소의 배열 만 전달할 수 있으므로 크기에 대한 추가 정보가 필요하지 않습니다. (그리고 다시 한 번, 당신은 할 수없는 배열을 전달 void foo( double*& )암시 적 변환의 결과가를 rvalue이며, const가 아닌 참조를 초기화 할 수 없습니다 당신은 사용해야합니다. void foo( double *const & );.
제임스 간제

1
대단한 :) 이것은 정확히 내가 찾던 것입니다. 나는 void foo(T &bar[N])내 템플릿에서 하고 있었지만 실제로는 "배열에 대한 참조"가 아니라 "참조의 배열"을 의미합니다.
OLL

그러한 함수가 이미 존재하고 가지고있는 모든 것이 std::vector(올바른 크기) 인 경우, 벡터의 내용 (아마를 통해 얻은 std::vector::data()) 을이 배열 유형으로 캐스트하는 방법은 무엇입니까? 유형 매개 변수의 고정 배열 크기에 대한 구문은 무엇입니까 (예 :와 함께 사용 static_cast<>)?
davidA

1
@meowsqueak 캐스트가 정의되지 않은 동작을 가질 것이기 때문에 당신은 그렇게하지 않을 것입니다. AFAICT; reinterpret_cast동적으로 할당 된 배열 (할당 후 고유 크기가 없음)을 고정 된 크기의 자동 배열로 처리하는 데 허용되지 않음을 알 수 있습니다 . 게다가 그것은 잘못된 질문입니다. 올바른 질문은 '어떻게 내 코드를 두 유형의 컨테이너와 함께 작동하도록 리팩터링 할 수 있습니까?'이고 대답은 템플릿과 반복기 / 범위 또는 크기가 고정되어 있다고 말 했으므로 함수입니다. 데이터 포인터 / 참조 만 취하고 크기를 하드 코딩합니다 (또는 크기가 다를 수있는 경우 데이터 / 크기 어댑터 (예 span
underscore_d

왜 void foo (double bar [])가 아닌가? 원한다면, array의 길이를 void foo (double bar [2])로 지정할 수도 있습니다. 복잡한 유형의 경우가 아니면 복사 생성자를 피해야합니다.
최종 원인

18

예,하지만 참조에 대한 인수 일치의 경우 포인터에 대한 암시 적 배열이 자동이 아니므로 다음과 같은 것이 필요합니다.

void foo( double (&array)[42] );

또는

void foo( double (&array)[] );

그러나 일치 할 때 double [42]double []구별되는 유형입니다. 알 수없는 차원의 배열이있는 경우 두 번째와 일치하지만 첫 번째는 일치하지 않으며 42 개 요소가있는 배열이있는 경우 첫 번째와 일치 하지만 두 번째는 일치 하지 않습니다 . (후자는 IMHO, 매우 반 직관적입니다.)

두 번째 경우에도 차원을 전달해야합니다. 함수 내부에 있으면 복구 할 방법이 없기 때문입니다.


7
두 번째는 나를 위해 컴파일되지 않습니다.
jrok

나도 마찬가지입니다. 나는 그것이 컴파일러 버그 때문인지 아니면 내가 간과 한 표준의 어떤 것 때문인지 모르겠다. 나는 실제로 그것을하고 싶지 않았습니다. (치수는 템플릿 매개 변수 인 경우 첫 번째는 컴파일러가 당신을 위해 정확한 치수를 알아 내기 때문에 매우 유용합니다.)
제임스 간제

6
두 번째 예제가 C ++를 준수하는 유효한 표준이라고 생각하지 않습니다. 덧붙여서 GCC 4.8 또는 Clang 3.4로 컴파일되지 않습니다. 템플릿 크기가 필요하다고 생각합니다.
Ricky65

2
@ Ricky65 그래서 그렇습니다. 이유가 궁금합니다. 불완전한 유형에 대한 참조는 일반적으로 함수 매개 변수로 허용됩니다. 이 완료되면 (물론,이 경우, 유형 변경 : double []double [42]. 두 가지 유형을 당신이 후자의 형태로 전달할 수있는 유일한 것은 알 수없는 길이, 예를 들어 배열 될 것이다 그래서 extern double d[];, 또는 같은 어떤 심각. 사용성을 제한합니다.)
James Kanze 2014 년

6

요소 만 수정하려는 경우 :

void foo(double *bar);

충분합니다.

주소를 (예 :)로 수정하고 realloc싶지만 배열에서 작동하지 않는 경우 :

void foo(double *&bar);

올바른 형식입니다.


4
후자에게 배열을 전달할 수 없다는 점을 제외하고는. 그는 포인터가 아닌 배열에 대해 물었습니다.
James Kanze

@JamesKanze : 사실입니다. 두 번째 경우는 스택의 배열에서 작동하지 않습니다.이 경우 첫 번째 형식을 사용해야합니다.
Naszta 2012

8
두 번째 경우는 배열에서 작동하지 않습니다. 포인터 유형의 실제 변수가있는 경우에만 작동합니다.
James Kanze


3

8.3.5.8 매개 변수의 유형이 "T의 알려지지 않은 경계의 배열에 대한 포인터"또는 "T의 알려지지 않은 경계의 배열에 대한 참조"형식의 유형을 포함하는 경우 프로그램은 잘못된 형식입니다.


2

다른 대답은 말합니다 마찬가지로 넣어 &애프터 *.

이것은 때때로 혼란 스러울 수있는 흥미로운 점을 가져옵니다. 유형은 오른쪽에서 왼쪽으로 읽어야합니다. 예를 들어, 이것은 (맨 오른쪽부터 시작 *하여) int에 대한 상수 포인터에 대한 포인터입니다.

int * const *x;

따라서 당신이 쓴 것은 참조에 대한 포인터가 될 것입니다.


순서를 변경해도 배열을 전달할 수 없습니다. 변환 결과가 아닌 실제 포인터 개체가 필요합니다.
James Kanze

1

여기에서 Erik 은 참조로 배열을 전달하는 모든 방법을 설명합니다 . https://stackoverflow.com/a/5724184/5090928 .

마찬가지로 다음 과 같이 배열 참조 변수를 만들 수 있습니다 .

int arr1[] = {1, 2, 3, 4, 5};
int(&arr2)[5] = arr1;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.