C ++에서“int & foo ()”는 무엇을 의미합니까?


114

lvalues ​​및 rvalues에 대한이 설명 을 읽는 동안 다음 코드 줄이 나에게 붙어 있습니다.

int& foo();
foo() = 42; // OK, foo() is an lvalue

g ++에서 시도했지만 컴파일러는 "foo ()에 대한 정의되지 않은 참조"라고 말합니다. 내가 추가하면

int foo()
{
  return 2;
}

int main()
{
  int& foo();
  foo() = 42;
}

잘 컴파일되지만 실행하면 세그멘테이션 오류가 발생 합니다. 그냥 라인

int& foo();

자체적으로 문제없이 컴파일 및 실행됩니다.

이 코드는 무엇을 의미합니까? 함수 호출에 값을 어떻게 할당 할 수 있으며 왜 이것이 rvalue가 아닌가?


25
함수 호출에 값을 할당하지 않고 반환하는 참조에 값을 할당 합니다 .
Frédéric Hamidi

3
@ FrédéricHamidi가 반환 된 참조가 참조하는 객체에 값을 할당
MM

3
예, 객체의 별칭입니다. 참조는 객체가 아닙니다
MM

2
@RoyFalk 로컬 함수 선언은 수두입니다. 개인적으로 언어에서 제거되는 것을 보게되어 기쁩니다. (물론 람다 제외)
MM

4
이에 대한 GCC 버그 가 이미 있습니다 .
jotik

답변:


168

설명은 foo유효한에 대한 lvalue 참조를 반환하는 합리적인 구현이 있다고 가정 합니다 int.

이러한 구현은 다음과 같습니다.

int a = 2; //global variable, lives until program termination

int& foo() {
    return a;
} 

이제는 foolvalue 참조를 반환하므로 다음과 같이 반환 값에 무언가를 할당 할 수 있습니다.

foo() = 42;

이것은 변수에 직접 액세스하거나 다시 호출하여 확인할 수 a있는 값으로 전역 을 업데이트 합니다.42foo

int main() {
    foo() = 42;
    std::cout << a;     //prints 42
    std::cout << foo(); //also prints 42
}

operator []에서와 같이 합리적입니까? 아니면 다른 회원 액세스 방법?
Jan Dorniak

8
굴절에 대한 혼란을 감안할 때 샘플에서 정적 지역 변수를 제거하는 것이 가장 좋습니다. 초기화는 불필요한 복잡성을 추가하므로 학습에 장애가됩니다. 글로벌로 만드십시오.
Mooing Duck 2016

72

다른 모든 답변은 함수 내부에서 정적을 선언합니다. 혼란 스러울 수 있으니 다음을 살펴보세요.

int& highest(int  & i, int  & j)
{
    if (i > j)
    {
        return i;
    }
    return j;
}

int main()
{
    int a{ 3};
    int b{ 4 };
    highest(a, b) = 11;
    return 0;
}

highest()참조를 반환 하기 때문에 여기 에 값을 할당 할 수 있습니다. 이것이 실행되면 b11로 변경됩니다. a예를 들어 8과 같이 초기화를 a변경하면 11로 변경됩니다. 이것은 다른 예제와 달리 실제로 목적에 맞는 코드입니다.


5
int a = 3 대신 int a {3}를 작성하는 이유가 있습니까? 이 구문은 나에게 적절하지 않은 것 같습니다.
Aleksei Petrenko 2016

6
@AlexPetrenko는 범용 초기화입니다. 나는 내가 편리한 예에서 그것을 사용하고 있었다. 그것에 대해 부적절 아무것도
케이트 그레고리

3
나는 이것이 무엇인지 압니다. a = 3은 훨씬 더 깔끔하게 느껴집니다. 개인 선호)
Aleksei Petrenko

함수 내에서 정적 선언이 일부 사람들을 혼란스럽게 할 수있는 것처럼 범용 초기화를 사용하는 것이 그럴 가능성이 있다고 생각합니다.
ericcurtin

@AlekseiPetrenko int a = 1.3의 경우 암시 적으로 a = 1로 변환됩니다. 반면 int a {1.3}은 오류를 발생시킵니다 : 축소 변환.
Sathvik

32
int& foo();

에 대한 참조를 반환하는 foo라는 함수를 선언합니다 int. 이 예제가 실패한 것은 컴파일 할 수있는 함수의 정의를 제공하는 것입니다. 우리가 사용한다면

int & foo()
{
    static int bar = 0;
    return bar;
}

이제에 대한 참조를 반환하는 함수가 있습니다 bar. 막대는 static함수 호출 후 계속 유지되므로 참조를 반환하는 것이 안전합니다. 이제 우리가

foo() = 42;

bar참조에 할당하고 참조는에 대한 별칭 일 뿐이므로 42를 할당합니다 bar. 다음과 같이 함수를 다시 호출하면

std::cout << foo();

bar위에 설정 했으므로 42를 인쇄 합니다.


15

int &foo();foo()반환 유형으로 호출 된 함수를 선언합니다 int&. 본문을 제공하지 않고이 함수를 호출하면 정의되지 않은 참조 오류가 발생할 수 있습니다.

두 번째 시도에서 함수를 제공했습니다 int foo(). 에서 선언 한 함수에 대한 반환 유형이 다릅니다 int& foo();. 따라서 foo일치하지 않는 동일한 선언이 두 개 있으며 , 이는 정의되지 않은 동작을 유발하는 단일 정의 규칙을 위반합니다 (진단 필요 없음).

작동하는 것을 위해 로컬 함수 선언을 제거하십시오. 그들은 당신이 본 것처럼 조용하고 정의되지 않은 동작으로 이어질 수 있습니다. 대신 함수 외부에서만 함수 선언을 사용하십시오. 프로그램은 다음과 같습니다.

int &foo()
{
    static int i = 2;
    return i;
}  

int main()
{
    ++foo();  
    std::cout << foo() << '\n';
}

10

int& foo();에 대한 참조를 반환하는 함수 int입니다. 제공된 함수는 int참조없이 반환 됩니다.

당신은 할 수 있습니다

int& foo()
{
    static int i = 42;
    return i;
}

int main()
{
    int& foo();
    foo() = 42;
}

7

int & foo();이는 foo()변수에 대한 참조를 반환 함을 의미합니다 .

이 코드를 고려하십시오.

#include <iostream>
int k = 0;

int &foo()
{
    return k;
}

int main(int argc,char **argv)
{
    k = 4;
    foo() = 5;
    std::cout << "k=" << k << "\n";
    return 0;
}

이 코드는 다음을 인쇄합니다.

$ ./a.out k = 5

때문에 foo()반환 전역 변수에 대한 참조 k.

수정 된 코드에서 반환 된 값을 참조로 캐스팅 한 후 유효하지 않습니다.


5

그 맥락에서 &는 참조를 의미하므로 foo는 int가 아닌 int에 대한 참조를 반환합니다.

아직 포인터로 작업했는지 확실하지 않지만 비슷한 생각입니다. 실제로 함수에서 값을 반환하지 않습니다. 대신 메모리에서 위치를 찾는 데 필요한 정보를 전달하는 것입니다. int입니다.

요약하면 함수 호출에 값을 할당하는 것이 아닙니다. 함수를 사용하여 참조를 얻은 다음 참조되는 값을 새 값에 할당합니다. 모든 것이 한 번에 일어난다 고 생각하기 쉽지만 실제로 컴퓨터는 모든 것을 정확한 순서로 수행합니다.

궁금한 점이 있다면-segfault가 발생하는 이유는 숫자 리터럴 '2'를 반환하기 때문입니다. 따라서 const int를 정의한 다음 수정하려고하면 얻을 수있는 정확한 오류입니다. 값.

포인터와 동적 메모리에 대해 아직 배우지 않았다면 한 번에 모두 배우지 않으면 이해하기 어려운 몇 가지 개념이 있으므로 먼저 권장합니다.


4

링크 된 페이지의 예제 코드는 단지 더미 함수 선언입니다. 컴파일되지는 않지만 정의 된 함수가 있으면 일반적으로 작동합니다. 예는 "이 서명이있는 함수가 있다면 그렇게 사용할 수 있습니다"를 의미했습니다.

귀하의 예에서는 foo서명을 기반으로 lvalue를 명확하게 반환하지만 lvalue로 변환 된 rvalue를 반환합니다. 이것은 분명히 실패로 결정됩니다. 다음과 같이 할 수 있습니다.

int& foo()
{
    static int x;
    return x;
}

다음과 같이 말할 때 x 값을 변경하여 성공합니다.

foo() = 10;

3

가지고있는 함수 인 foo ()는 정수에 대한 참조를 반환하는 함수입니다.

따라서 원래 foo가 5를 반환하고 나중에 주 함수에서라고 말한 foo() = 10;다음 foo를 출력하면 5 대신 10을 출력 한다고 가정 해 보겠습니다 .

나는 그것이 의미가 있기를 바랍니다 :)

프로그래밍도 처음입니다. 이렇게 생각하게 만드는 질문을 보는 것은 흥미 롭습니다! :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.