2009-10-23 4 views
8

IBM XL C/C++ 컴파일러에서이 경고가 나오는 이유는 무엇입니까?

#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를 시도했지만 아무런 진단도 얻지 못했습니다. 여기에 복사 생성자에 대한 액세스가 필요한 이유는 무엇입니까? 객체를 복사 할 수 없도록 만들거나 (실제 제어 객체가 복사하는 데 비용이 많이 드는) 명시적인 사본을 전달하는 것 외에 경고를 어떻게 제거 할 수 있습니까?

+0

실제로 클래스의 구현 내에서 복사 생성자를 사용하고 있습니까? –

+0

아니요. 진단서를 작성한 전체 코드 파일을 게시했습니다. –

+0

FYI : VC++ 2005 및 2008에서도 경고없이 컴파일을 시도했습니다. 그래서 당신 말이 맞아 보인다, 문제는 오히려 IBM 컴파일러 특정 것 같다 – jdehaan

답변

9

규칙은 표준의 §8.5.3/5에 있습니다. 세 가지 기본 상황이 확인되었습니다. 첫 번째는 lvalue이거나 클래스 유형을 갖는 이니셜 라이저 (귀하의 경우 '3')와 관련됩니다. 이들 중 어느 것도 사실이 아니기 때문에 클래스 유형이없는 rvalue로 const 참조를 초기화하는 세 번째 경우가 있습니다. 이 경우는 8.5.3/5의 마지막 글 머리 기호로 처리됩니다.

Otherwise, a temporary of type “cv1 T1” is created and initialized from the initializer expression using the rules for a non-reference copy initialization (8.5). The reference is then bound to the temporary. If T1 is reference-related to T2, cv1 must be the same cv-qualification as, or greater cv-qualification than, cv2; otherwise, the program is ill-formed.

편집 : 다시 읽으면 IBM이 맞다고 생각합니다. 나는 이전에 임시 파일을 복사 할 필요성을 생각하고 있었지만 문제의 원인이 아닙니다. §8.5에 명시된 바와 같이 비표준 사본 초기화를 사용하여 임시 사본을 만들려면 사본 사본이 필요합니다. 특히이 시점에서 다음과 같은 표현식과 같습니다 :

Tx = a;

이것은 기본적으로 다음과 같습니다.

Tx = T (a);

e.e. 임시 객체를 생성 한 다음, 임시 객체를 초기화 할 객체에 복사해야합니다 (이 경우 도 임시로 임). 필요한 과정을 요약하면, 그것은 같은 코드와 거의 비슷이다 :

T temp1(3); 
T temp2(temp1); // requires copy ctor 
show(temp2); // show's reference parameter binds directly to temp2 
+0

좋은 정보. 연구에 감사드립니다, Jerry. –

+0

정말 이상 하긴하지만 표준에 대한/IBM의 독서에 동의합니다. –

+0

임시적으로는을 생성해야합니다. 임시로 생성하려면 __be able__이 (가) 필요합니다. 기술적으로 컴파일러는이를 최적화 할 수 있습니다. –

3

C++은 as-if 규칙 중 하나를 위반하여 임시 객체를 복사하지 않도록 충분히 스마트 한 컴파일러를 허용합니다. IBM의 AIX C++ 컴파일러에 익숙하지 않지만 show(3) 호출에 임시 Thing을 복사해야한다고 생각하는 것 같습니다. 이 경우 C++에서는 컴파일러가 사용하기가 어려울 정도로 스마트 한 경우에도 액세스 가능한 복사 생성자가 있어야합니다.

하지만 show(3)은 왜 처음부터 복사해야합니까? 나는 그것을 알 수 없다. 행운과 함께, litb 조금 따라있을 것입니다.

+0

그건 내가 생각했던 거의예요. –

+0

"하지만 왜 show (3)는 처음부터 복사본이 필요합니까?" 나는 그것이해야한다고 생각하지 않는다. 코드는 임시 객체를 생성하고 그 객체를'const Thing &'함수 매개 변수에 직접 바인딩해야합니다. 제리가 옳다고 생각합니다. 이것은 버그입니다. – sbi

+0

표준을 다시 읽은 후에 버그가 아닌 것으로 확신합니다. –

0

임시 대상의 이름을 지정하면 어떻게됩니까? 이것에 대한

Thing temp(3);
show(temp);

+0

이렇게하면 메시지가 제거됩니다. 아마 본질적으로 이것을 할 것이지만 아마도 힙 할당을 할 것입니다. 그만큼 빠르지는 않지만 실물 크기의 물체는 꽤 큽니다. 어쨌든 임시에 의존하지 않는 것이 더 나을 것입니다. –

1

내 직감은 제리의 answer이 올바른지,하지만 몇 가지 질문이 아직 없습니다.

흥미로운 점은 해당 섹션의 앞 단락 (391)을 다루는 핵심 문제가 있다는 것입니다.이 문제는 인수가 같은 클래스 유형 인 경우와 관련됩니다. 특히 :있는 임시를 rvalue가 같은 클래스 유형이 곳

int main() { 
    show (Thing (3));  // not allowed under current wording 
          // but allowed with Core Issue 391 

    show (3);    // Still illegal with 391 
} 

핵심 문제 391의 변화에만 영향을줍니다. 이전 문구가 있었다 : 마지막 줄이 현재의 표준에 따라 show(Thing(3)) 불법 만들 것입니다 무엇

If the initializer expression is an rvalue, with T2 a class type, and cv1 T1 is reference-compatible with cv2 T2, the reference is bound as follows:

[...]

The constructor that would be used to make the copy shall be callable whether or not the copy is actually done.

있다. 이 섹션에 대한 제안 표현은 :이 시점에서

If the initializer expression is an rvalue, with T2 a class type, and "cv1 T1" is reference-compatible with "cv2 T2", the reference is bound to the object represented by the rvalue (see 3.10 [basic.lval]) or to a sub-object within that object.

, 나는 g ++뿐만 391 당하지만 변화가 실수로 복사 초기화 케이스를 포함하는 것이 동작을 업데이트 한 수 있다고 판단. 그러나, 나는 다른 컴파일러 행동 사이의되는 불일치로 인해 의심이 수행

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) 
} 

나는 foo (3) 경우에 대한 제리의 해석에 오류를 찾을 수 없습니다 : 그러나,이 내가 테스트 g의 ++의 버전에 의해 입증되지 .

관련 문제