오류 : 'int'유형의 rvalue에서 'int &'유형의 상수가 아닌 참조를 잘못 초기화했습니다.


87

잘못된 형식 :

int &z = 12;

올바른 형식 :

int y;
int &r = y;

질문 :
첫 번째 코드가 잘못된 이유는 무엇입니까? 제목에있는 오류의 " 의미 "는 무엇입니까?


4
임시는 상수가 아닌 참조에 바인딩 될 수 없습니다. 이 경우 int (12)는 임시입니다.
Prasoon Saurav 2011

@PrasoonSaurav 임시 12는 무엇을 의미합니까? 여기에 개념의 부족 (내 부분 :))
Aquarius_Girl

2
이 제한에 대한 엄격한 기술적 이유 는 없습니다 . 임시에 대한 변경 가능한 참조를 허용 하는 것도 구현하기 쉬웠을 것 입니다. 금지하는 것은 C ++ 의 설계 결정 입니다. 그러한 구조는 진짜 유틸리티보다 부주의하게 남용 될 위험이 훨씬 더 큰 열악한 설계이기 때문입니다. (저는 그런 것에 대한 인위적인 필요를 한 번만 발견했습니다.)
Kerrek SB

@KerrekSB rvalue 객체에 대한 바인딩 참조에 대한 가장 일반적인 필요는 아마도(ostringstream() << "x=" << x).str()
curiousguy

@curiousguy : 네, 제가 게시 한 링크의 내용입니다.
Kerrek SB 2011

답변:


132

C ++ 03 3.10 / 1은 "모든 표현식은 lvalue 또는 rvalue입니다."라고 말합니다. lvalueness 대 rvalueness는 객체가 아니라 표현식의 속성이라는 것을 기억하는 것이 중요합니다.

Lvalues는 단일 식 이상으로 지속되는 개체의 이름을 지정합니다. 예를 들어, obj, *ptr, ptr[index], 및 ++x모든 lvalues입니다.

Rvalue는 그들이 살고있는 전체 표현의 끝에서 증발하는 임시입니다 ( "세미콜론에서"). 예를 들어, 1729, x + y, std::string("meow"), 및 x++모든 우변입니다.

연산자의 주소는 "피연산자가 lvalue이어야 함"을 요구합니다. 한 표현식의 주소를 취할 수 있다면 표현식은 lvalue이고 그렇지 않으면 rvalue입니다.

 &obj; //  valid
 &12;  //invalid

2
" 만약 우리가 하나의 표현의 주소를 취할 수 있다면, 그 표현은 lvalue이고, 그렇지 않으면 그것은 rvalue입니다. "만약 C ++만이 그렇게 간단하다면! (그러나 여기서 뉘앙스는 실제로 관련이 없습니다) "Rvalues는 일시적입니다"일시적인 무엇입니까? 사물?
curiousguy

2
@curiousguyRvalues는 그들이 살고있는 완전한 표현의 끝에서 사라지는 일시적입니다. 단순히 표현 int & = 12;이 유효하지 않은 이유에 답하기 위해 표준은 문자열 리터럴은 lvalue이고 다른 리터럴은 rvalue라고 말합니다.
BruceAdi 2011

@curiousguy : 네. Rvalue는 임시 객체 이지만 모든 rvalue가 임시 객체는 아닙니다. 일부는 사물이 아닙니다.
Nawaz

" 예를 들어, 1729, x + y, std :: string ("meow ") 및 x ++는 모두 rvalue입니다 . "그러나 std::string("meow")유형의 객체를 std::string생성하고이 객체를 지정하는 rvalue를 생성하고 1729부작용이 없으며 값을 생성합니다. 유형의 rvalue로 1729 int.
curiousguy

1
@curiousguy :이 진술 "Lvalues name objects that persist beyond a single expression."은 100 % 정확한 진술입니다. 반대로, (const int &)1"명명 된"객체가 아니기 때문에 귀하의 예제 는 올바르지 않습니다.
Nawaz 2011

53
int &z = 12;

오른쪽 int에는 정수 리터럴에서 임시 개체 유형 이 만들어 12지지만 임시 개체는 상수 가 아닌 참조에 바인딩 될 수 없습니다. 따라서 오류입니다. 다음과 같습니다.

int &z = int(12); //still same error

임시가 생성되는 이유는 무엇입니까? 참조는 메모리에있는 객체를 참조해야하고 객체가 존재하려면 먼저 생성되어야합니다. 개체의 이름이 지정되지 않았기 때문에 임시 개체입니다. 이름이 없습니다. 이 설명에서 두 번째 경우가 좋은 이유가 꽤 분명해졌습니다.

임시 객체는 const 참조에 바인딩 될 수 있습니다. 즉, 다음과 같이 할 수 있습니다.

const int &z = 12; //ok

C ++ 11 및 Rvalue 참조 :

완전성을 위해 C ++ 11에 임시 개체에 바인딩 할 수있는 rvalue-reference가 도입되었음을 추가하고 싶습니다. 따라서 C ++ 11에서는 다음과 같이 작성할 수 있습니다.

int && z = 12; //C+11 only 

&&intead가 &있습니다. 또한 바인딩 const하는 객체가 zinteger -literal에서 생성 된 임시 객체 인 경우에도 더 이상 필요하지 않습니다 12.

C ++ 11 도입 이후 r- 수치 참조 , int&지금부터는라고 좌변 참조 .


10

12에서 참조하는 데이터와 달리 변경할 수없는 컴파일 타임 상수입니다 int&. 당신이 할 있는 것은

const int& z = 12;

2
@curiousguy, 일관성을 유지하세요. "이것들이 C ++ 규칙이라는 것을 이해해야합니다.이 규칙은 존재하며 정당화가 필요하지 않습니다"(초판은 말할 것도 없습니다). 필요하지 않은 것을 자신에 따라주지 않는다는 당신의 불평을 어떻게 해석해야합니까?
Michael Krelin-해커

2
@ MichaelKrelin-hacker : 기술적으로는 그렇지 않습니다. 참조를 값 (또는 컴파일 시간 상수)에 바인딩 할 수 없습니다. 표준은 실제로 발생하는 일에 대해 매우 명시 적입니다. 그렇지 않으면 "cv1 T1"유형의 임시가 생성되고 비 참조 복사 초기화 (8.5)에 대한 규칙을 사용하여 이니셜 라이저 표현식에서 초기화됩니다. 그런 다음 참조는 임시에 바인딩됩니다. 즉, 구문이 허용되지만 의미는 상수에 대한 참조를 바인딩하는 것이 아니라 암시 적으로 생성 된 임시에 바인딩하는 의미입니다.
David Rodríguez-dribeas

1
@curiousguy : 언어의 규칙은 디자인의 일부이며, 종종 언어가 그렇게 디자인 된 이유에 대한 정당성이 있습니다. 이 특별한 경우에는 C에서와 같이 값의 주소를 사용할 수 없으며 (값이 없음) 참조를 바인딩 할 수 없습니다. 이제 void f( vector<int> const & )수정되지 않는 벡터를 전달하는 관용적 함수를 고려하십시오 . 이제 문제는 그것이 f( vector<int>(5) )올바르지 않으며 사용자 void f( vector<int> v ) { f(v); }가 사소한 다른 과부하를 제공해야한다는 것입니다.
David Rodríguez-dribeas

1
... 이제는 언어 사용자에게 고통 스러울 것이기 때문에 디자이너는 컴파일러가 동등한 작업을 수행하기로 결정했습니다. 호출 f( vector<int>(5) )에서 컴파일러는 임시를 만든 다음 해당 임시에 대한 참조를 바인딩하고 유사하게 5직접 암시 적 변환이있는 경우 . 이를 통해 컴파일러는 함수에 대한 단일 서명을 생성하고 단일 사용자가 함수를 구현할 수 있습니다. 이후부터는 일관성을 위해 나머지 상수 참조 사용에 대해 유사한 동작이 정의됩니다.
David Rodríguez-dribeas

1
@ MichaelKrelin-hacker : 참조는 객체에 대한 별칭 이며 값은 객체가 아닙니다. 다만 상황에 따라 참조 할 수있다 별명을 컴파일러가 참조를 제거하고 단지 원래의 목적은 의미가 어떤 의미하는 식별자를 사용 ( T const & r = *ptr;의 이후 사용 r하는 기능에 의해 대체 될 수 *ptrr런타임에 존재 할 필요가 없습니다) 또는 별칭이 지정된 객체의 주소를 유지하여 구현해야 할 수도 있습니다 (참조를 객체의 구성원으로 저장하는 것을 고려). 이는 자동 역 참조 된 포인터로 구현됩니다.
David Rodríguez-dribeas

4

non-const 및 const 참조 바인딩은 다른 규칙을 따릅니다.

다음은 C ++ 언어의 규칙입니다.

  • 리터럴 숫자 ( 12) 로 구성된 표현식 은 "rvalue"입니다.
  • rvalue로 상수가 아닌 참조를 만드는 것은 허용되지 않습니다. 형식 int &ri = 12;이 잘못되었습니다.
  • rvalue를 사용하여 const 참조를 만들 수 있습니다.이 경우 명명되지 않은 개체가 컴파일러에 의해 생성됩니다. 이 객체는 참조 자체가 존재하는 한 지속됩니다.

이것이 C ++ 규칙이라는 것을 이해해야합니다. 그들은 단지 그렇습니다.

약간 다른 규칙을 사용하여 다른 언어, 예를 들어 C ++ '를 만드는 것은 쉽습니다. C ++ '에서는 rvalue를 사용하여 상수가 아닌 참조를 만들 수 있습니다. 여기에는 일관성이 없거나 불가능한 것이 없습니다.

그러나 그것은 프로그래머가 의도 한 것을 얻지 못할 수도있는 위험한 코드를 허용 할 것이고, C ++ 디자이너는 그 위험을 피하기로 올바르게 결정했습니다.


0

참조는 변경할 수있는 항목 (lvalue)에 대한 "숨겨진 포인터"(null이 아님)입니다. 상수로 정의 할 수 없습니다. "변수"여야합니다.

편집하다::

나는 생각하고있다

int &x = y;

거의 동등한

int* __px = &y;
#define x (*__px)

여기서 __px새로운 이름이고, 상기는 #define x단지 선언 함유 블록 내부 작동 x참조.


1
왜 할 수 있습니다, 참조 인 경우 const:
해커 - 마이클 Krelin

그러나 포스터의 예는 아니었다const
실레 Starynkevitch

네, "참조는 변경 될 수있는 것들에 대한 포인터입니다"라는 말은 비용이 들지 않는 참조에 관한 것입니다.
Michael Krelin-해커

" 참조는"숨겨진 포인터 " "잘못됨 " 변경 될 수있는 "잘못됨 " 변경 될 수있는 것 (lvalues) "잘못됨
curiousguy

@Loki : 더 설명해 주시겠습니까?
Basile Starynkevitch
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.