문제

다음은 문제를 설명하는 최소 코드 예제입니다.

#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);

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top