참조 유형 변환 연산자 : 문제를 요구합니까?
-
22-07-2019 - |
문제
다음 코드를 사용하여 컴파일하면 g++
class A {};
void foo(A&) {}
int main()
{
foo(A());
return 0;
}
다음 오류 메시지가 표시됩니다.
> g++ test.cpp -o test
test.cpp: In function ‘int main()’:
test.cpp:10: error: invalid initialization of non-const reference of type ‘A&’ from a temporary of type ‘A’
test.cpp:6: error: in passing argument 1 of ‘void foo(A&)’
약간의 반성 후, 이러한 오류는 나에게 많은 의미가 있습니다. A()
스택에 할당 가능한 위치가 아니라 일시적인 가치이므로 주소가없는 것 같습니다. 주소가 없다면 주소를 참조 할 수 없습니다. 좋아.
하지만 기다려! 다음 변환 연산자를 클래스에 추가하면 A
class A
{
public:
operator A&() { return *this; }
};
그렇다면 모두 잘됩니다! 내 질문은 이것이 원격으로 안전한 지 여부입니다. 정확히 무엇을 하는가 this
언제를 가리 킵니다 A()
임시 가치로 구성되어 있습니까?
나는 그 사실로 인해 약간의 자신감을 얻었습니다
void foo(const A&) {}
다음에 따라 임시 값을 수락 할 수 있습니다 g++
그리고 내가 사용한 다른 모든 컴파일러. 그만큼 const
키워드는 항상 캐스트 될 수 있으므로 A 사이에 실제 의미 적 차이가 있으면 놀랄 것입니다. const A&
매개 변수와 an A&
매개 변수. 그래서 나는 그것이 내 질문을하는 또 다른 방법이라고 생각합니다. 왜 const
컴파일러가 안전한 것으로 간주되는 임시 가치에 대한 참조는const
참조는 아니야?
해결책
주소를 가져갈 수는 없다는 것은 아닙니다 (컴파일러가 항상 스택에서 깎아내는 순서를 주문할 수 있습니다. A &를 취하는 인터페이스를 사용하면 "이 매개 변수의 내용을 수정하여 기능 호출 후 읽을 수 있습니다"라고 말합니다. 당신이 그것을 일시적으로 전달하면, 함수 후에 "수정 된"것은 존재하지 않습니다. 이것은 (아마도) 프로그래밍 오류이므로 허용되지 않습니다. 예를 들어, 고려하십시오.
void plus_one(int & x) { ++x; }
int main() {
int x = 2;
float f = 10.0;
plus_one(x); plus_one(f);
cout << x << endl << f << endl;
}
이것은 컴파일되지 않지만, 임시가 불안정에 묶을 수 있다면 컴파일하지만 놀라운 결과를 얻을 수 있습니다. plus_one (f)에서 f는 임시 int로 암시 적으로 변환 될 것입니다. Plus_one은 온도를 가져 와서 그것을 증가시켜 기본 플로트 F를 그대로 유지합니다. plus_one이 돌아 왔을 때, 그것은 효과가 없었을 것입니다. 이것은 거의 확실히 프로그래머가 의도 한 것이 아닙니다.
규칙은 때때로 엉망입니다. 일반적인 예 (설명 여기), 파일을 열고 인쇄하고 닫으려고합니다. 당신은 할 수 있기를 원할 것입니다 :
ofstream("bar.t") << "flah";
그러나 연산자 <<이 참조를 사용하기 때문에 할 수는 없습니다. 옵션은 두 줄로 나누거나 ref-to-non-const를 반환하는 메소드를 호출합니다.
ofstream("bar.t").flush() << "flah";
다른 팁
R- 값을 Const 참조에 할당하면 참조가 파괴 될 때까지 임시가 파괴되지 않음을 보장합니다. 정점이 아닌 참조에 할당하면 그러한 보증이 없습니다.
int main()
{
const A& a2= A(); // this is fine, and the temporary will last until the end of the current scope.
A& a1 = A(); // You can't do this.
}
당신은 willy nilly를 안전하게 캐스트 할 수 없으며 일이 효과가있을 것으로 기대합니다. Const 및 Nonst 참조에는 다른 의미론이 있습니다.
일부 사람들이 들어갈 수있는 gotcha : MSVC 컴파일러 (Visual Studio Compiler, Visual Studio 2008로 확인) ~ 할 것이다 이 코드를 문제없이 컴파일하십시오. 우리는 일반적으로 하나의 인수 (소화 할 데이터 덩어리)를 취한 기능을 위해이 패러다임을 사용하고 있었지만 때로는 청크를 검색하고 발신자에게 다시 결과를 얻기를 원했습니다. 다른 모드는 세 가지 인수를 받아 활성화되었습니다. 두 번째 인수는 검색 할 정보 (빈 문자열에 대한 기본 참조)이며 세 번째 인수는 반환 데이터 (원하는 유형의 빈 목록에 대한 기본 참조)에 대한 것이 었습니다.
이 패러다임은 Visual Studio 2005와 2008에서 작동했으며, 우리는 G ++로 컴파일하기 위해 소유 한 소유자 대신 목록이 구축되고 반환되도록 리팩터링해야했습니다.
컴파일러 스위치를 MSVC에서 이런 종류의 동작을 허용하지 않도록 설정하거나 G ++에서 허용하는 방법이 있다면 알게되어 기쁩니다. G ++ 컴파일러의 MSVC 컴파일러 / 제한성의 허용 성은 포팅 코드에 합병증을 추가합니다.