왜 IBM XL C/C ++ 컴파일러의 경고?
-
06-07-2019 - |
문제
다음은 문제를 설명하는 최소 코드 예제입니다.
#include <iostream>
class Thing
{
// Non-copyable
Thing(const Thing&);
Thing& operator=(const Thing&);
int n_;
public:
Thing(int n) : n_(n) {}
int getValue() const { return n_;}
};
void show(const Thing& t)
{
std::cout << t.getValue() << std::endl;
}
int main()
{
show(3);
}
이것은 동일한 오류를 산출합니다.
int main()
{
show( Thing(3) );
}
AIX의 IBM XL C/C ++ 8.0 컴파일러는 이러한 경고를 방출합니다.
"testWarning.cpp", line 24.9: 1540-0306 (W) The "private" copy constructor "Thing(const Thing &)" cannot be accessed.
"testWarning.cpp", line 24.9: 1540-0308 (I) The semantics specify that a temporary object must be constructed.
"testWarning.cpp", line 24.9: 1540-0309 (I) The temporary is not constructed, but the copy constructor must be accessible.
또한 "-wall"및 "-pedantic"으로 G ++ 4.1.2를 시도했으며 진단을받지 못했습니다. 여기에서 카피 생성기에 대한 액세스가 필요한 이유는 무엇입니까? 객체를 복사 할 수있는 것 외에 (내 컨트롤 외부에 있음), 명시적인 사본을 통과 할 수있는 것 외에 경고를 제거하려면 어떻게해야합니까 (실제 객체가 복사 비용이 많이 드는 경우)?
해결책
이 규칙은 표준의 §8.5.3/5에 있습니다. 식별 된 세 가지 기본 상황이 있습니다. 첫 번째는 이니셜 라이저 ( '3')가 lValue이거나 클래스 유형을 갖는 것을 포함합니다. 그 중 어느 것도 사실이 아니기 때문에, 당신이 가진 것은 세 번째 사례입니다. 클래스 유형이없는 rvalue로 const 참조를 초기화합니다. 이 경우는 8.5.3/5의 최종 총알로 덮여 있습니다.
그렇지 않으면, 비 참조 사본 초기화 (8.5)에 대한 규칙을 사용하여 초기 "CV1 T1"유형의 임시 유형이 생성되고 초기화됩니다. 그런 다음 참조는 임시로 묶여 있습니다. T1이 T2에 대한 기준 관련이면 CV1은 CV2와 동일한 CV- 자격이 있어야합니다. 그렇지 않으면 프로그램이 잘못되었습니다.
편집 : 다시 읽음, IBM이 제대로되어 있다고 생각합니다. 나는 이전에 임시를 복사해야 할 가능성을 생각하고 있었지만 그것은 문제의 원천이 아닙니다. §8.5에 지정된대로 비 참조 사본 초기화를 사용하여 임시를 만들려면 사본 CTOR가 필요합니다. 특히,이 시점에서 그것은 다음과 같은 표현과 동일합니다.
t x = a;
이것은 기본적으로 다음과 같습니다.
t x = t (a);
즉, 임시를 생성 한 다음 초기화되는 객체에 임시를 복사해야합니다 (이 경우에는 다음과 같습니다. 또한 임시). 필요한 프로세스를 요약하려면 다음과 같은 코드와 거의 같습니다.
T temp1(3);
T temp2(temp1); // requires copy ctor
show(temp2); // show's reference parameter binds directly to temp2
다른 팁
C ++는 임시 객체를 복사하지 않도록 충분히 스마트 한 컴파일러를 허용합니다. 마치 표준에 의해 허용되는 규칙. 나는 IBM의 AIX C ++ 컴파일러에 익숙하지 않지만 show(3)
전화는 일시적인 것을 복사해야합니다. 이 경우 C ++는 컴파일러를 사용하지 않을 정도로 똑똑하더라도 액세스 가능한 사본 생성자가 있어야합니다.
그러나 왜 show(3)
처음에 사본이 필요하십니까? 내가 알아낼 수 없다는 것. 운이 좋으면 Litb는 조금씩 진행될 것입니다.
내 직감은 Jerry의 느낌입니다 대답 정확하지만 여전히 몇 가지 질문이 있습니다.
흥미로운 점은 해당 섹션의 이전 단락을 다루는 핵심 문제가 있다는 것입니다.391). 이 문제는 인수가 동일한 클래스 유형 인시기와 관련이 있습니다. 구체적으로:
int main () {
show ( Thing (3) ); // not allowed under current wording
// but allowed with Core Issue 391
show ( 3 ); // Still illegal with 391
}
핵심 문제의 변화 391 RValue 임시가 동일한 클래스 유형을 갖는 경우에만 영향을줍니다. 이전의 문구는 다음과 같습니다.
이니셜 라이저 표현식이 RValue이고 T2 A 클래스 유형이있는 경우
cv1 T1
참조 호환입니다cv2 T2,
참조는 다음과 같이 바인딩됩니다.[...]
사본을 만드는 데 사용되는 생성자는 실제로 복사가 완료되었는지 여부에 관계없이 호출 할 수 있어야합니다.
그 마지막 줄은 만드는 것입니다 show(Thing(3))
현재 표준에 따라 불법. 이 섹션의 제안 된 문구는 다음과 같습니다.
이니셜 라이저 표현식이 RValue이고 T2 A 클래스 유형을 갖고 "CV1 T1"은 "CV2 T2"와 참조 호환되는 경우, 참조는 rvalue (3.10 [basic.lval] 참조) 또는 객체에 바인딩됩니다. 그 객체 내의 하위 객체에.
이 시점에서 G ++가 그 행동을 업데이트했을 수 있다고 생각했습니다. 391 그러나 변화에는 실수로 사본 초기화 사례가 포함되었습니다. 그러나 이는 내가 테스트 한 G ++의 버전으로 입증되지 않습니다.
class A{
public:
A ();
A (int);
private:
A (A const &);
};
void foo (A const &);
void foo ()
{
A a = 3 ; // 3.2.3 (ERROR), 3.4.6(ERROR), 4.4.0(ERROR), Comeau(ERROR)
foo ( 3 ) ; // 3.2.3 (OK), 3.4.6(OK), 4.4.0(OK), Comeau(OK)
foo ( A() ); // 3.2.3 (OK), 3.4.6(ERROR), 4.4.0(OK), Comeau(OK)
foo ( A(3) ); // 3.2.3 (OK), 3.4.6(ERROR), 4.4.0(OK), Comeau(OK)
}
Jerry의 해석에서 결함을 찾을 수 없습니다. foo (3)
그러나 사례는 다른 컴파일러 동작 사이의 불일치로 인해 의문이 있습니다.
일시적인 것을 지명하려고하면 어떻게됩니까?
Thing temp(3);
show(temp);