2011-04-30 8 views
0

아래 예외 클래스가 있습니다.왜 아래 코드가 VS2010에서 성공적으로 컴파일됩니까?

class ExceptionTest : std::exception 
{ 
public: 
ExceptionTest(int value): 
    m_value(value) 
{ 
} 
~ExceptionTest() 
{ 
} 
private: 
ExceptionTest(const ExceptionTest& test) 
{ 
} 

int m_value; 
}; 

그때 나는 이런 식으로 사용 -

int checkexception() 
{ 
throw ExceptionTest(2); 
} 

int main() 
{ 
try 
{ 
    checkexception(); 
} 
catch (ExceptionTest& exception) 
{ 
    cout<<"haha"; 
} 
return 1; 
} 

이 복사 생성자가 개인 인 경우에도 완벽하게 잘 작동합니다. 당신이 값으로 예외를 잡을 경우

실패 -

int main() 
{ 
try 
{ 
    checkexception(); 
} 
catch (ExceptionTest exception) --> this fails 
{ 
    cout<<"haha"; 
} 
return 1; 
} 

내가 오류는 I 클래스

에 복사 생성자를 정의하지 않는 경우

error C2316: 'ExceptionTest' : cannot be caught as the destructor and/or copy 
constructor are inaccessible 

내가 링커 오류입니다

class ExceptionTest : std::exception 
{ 
public: 
ExceptionTest(int value): 
    m_value(value) 
{ 
} 
~ExceptionTest() 
{ 
} 
private: 
ExceptionTest(const ExceptionTest& test); 

int m_value; 
}; 

링크 : C : \ Users \ sumitha \ Documents \ Visual Studio 2010 \ Projects \ test \ Debug \ test.exe not fo 마지막 증분 링크에 의해 생성되거나 생성되지 않음; 전체 링크 수행 1> main.obj : 오류 LNK2001 : 해결되지 않은 외부 기호 "개인 : __thiscall ExceptionTest :: ExceptionTest (클래스 ExceptionTest const &)"(0ExceptionTest @@ AAE @ ABV0 @@ Z) 1> C : \ Users \ sumitha \ Documents \ Visual Studio 2010 \ Projects \ test \ Debug \ test.exe : 치명적인 오류 LNK1120 : 해결되지 않은 외부가 ========== 빌드 : 0 성공, 1 실패, 0 up-to -date, 0 skipped ==========

위의 내용이 참이면 예외 클래스의 복사본 생성자를 항상 private으로 설정하여 호출자가 예외를 catch하도록 할 수 있습니다. 참고. 나는 이것이 "반환 가치 최적화"로 인해 일어나고 있다고 생각한다.

+2

저는 C + + 숙달이 아니기 때문에 & nbsp 원래의 예외에 대한 참조를 얻고 있다는 의미 일 수 있습니까? –

+0

여기에이 오래된 버그에 투표하십시오. https://connect.microsoft.com/VisualStudio/feedback/details/101545/incorrect-reference-to-base-class-copy-constructor-when-throwing-an-exception –

답변

5

이것은 VS2010의 C++ 구현에 오류가있는 것으로 보입니다.

표현식이 throw 인 경우 throw 식의 피연산자를 복사 (또는 이동)하여 임시 예외 객체가 만들어집니다. 표현식에 클래스 유형이 있으면 복사 (또는 이동) 생성자가 관련되며 생성자는 throw의 시점에서 액세스 할 수 있어야합니다. 예외 객체의 복사 생성자가 private 인 경우 해당 객체는 멤버 함수 또는 friend 함수에서만 throw 될 수 있습니다.

이 문제는 나중에 예외 개체가 값에 의해 또는 나중에 프로그램에서 참조로 catch되는지 여부와 완전히 독립적입니다.

임시 예외 개체를 생성 할 때 실제 복사본이 생략 될 수 있지만 C++에서는 사용 된 생성자가 여전히 액세스 가능해야합니다.

ISO/IEC 14882 : 2003 15.1 [except.throw]/5

임시 객체의 사용은 생성자와 소멸자의 실행을 제외한 프로그램의 의미를 변경하지 않고 제거 될 수 있다면 임시 객체 (12.2)의 사용과 관련되어 있으면 처리기의 예외를 throw 표현식의 인수로 직접 초기화 할 수 있습니다. Throw 된 객체가 클래스 객체이고 임시 복사본을 초기화하는 데 사용 된 복사 생성자가 액세스 할 수없는 경우 임시 객체를 제거 할 수있는 경우에도 프로그램이 잘못 구성됩니다. 마찬가지로 개체의 소멸자에 액세스 할 수없는 경우에도 임시 개체를 제거 할 수있는 경우에도 프로그램이 잘못 구성됩니다.

이 요구 사항은 C++ 0x에서 제거되지 않았지만 적절한 경우 복사되는 대신 표현식을 이동할 수 있습니다.

n3291 15.1 [except.throw]/5 초안 :

슬로우 객체 클래스 객체의 복사/이동 생성자이며 소멸자가 복사/이동 동작이있는 경우에도 접근 할 수 있어야 (12.8).

1

마리노 (Marino)와 마찬가지로 참조로 잡히면 복사 구성이 필요 없다.

그래서 컴파일러는 그것을 보지, 및 개인 생성자 : (!) 참고로

에 실패하지 않는, 내가 특별히 예외에 대한 '예외'(의도 웃기)에서이 있음을 기억 value-by-semantics에 관한 스펙. 나는 더 이상 구체적인 모르겠지만,

  • 이 경우 특히
  • 아마도 활성 스택을 풀기하면서 자연스럽게 조금 까다 롭습니다 자동 변수 (stackallocated)에서 지역의 예외를 전달과 관련이있다 값으로 잡힌 예외의 재발행의 예 :

.... 
catch (std::runtime_error e) 
{ 
    // .... 
    throw; 
} 
+0

It doesn 클래스 타입의 객체가 던져지면 복사 (또는 이동) 생성자는 그것이 던져지는 시점에서 접근 할 수 있어야한다. 왜냐하면 임시 예외 객체는 항상 copy- (또는 move-)가 피연산자로 구성됩니다. 이 복사본이 생략 되어도 사용 된 생성자는 여전히 액세스 가능해야합니다. –

+0

Arg. 때로는 C++에 두 개의 세계가 있다고 느낍니다. - 첫째로 핵심은 내가 일을 끝내게하고, 두 번째로 일종의 언어 레슬러/변호사 만 재생할 수있는 스펙과 놀라움의 어둡고 뒤죽박죽 된 게임입니다. 나는 결론에 도달했습니다. 이는 주로 상위 수준의 구조를 낮은 수준의 액세스에 연결하고 이식성 및 하위 호환성 요구 사항에 대한 관대 한 지원을 통해 교차 수유하는 본질적인 복잡성이라는 것입니다.나는 너희들이 왈츠와 감탄 하듯이 upvote하는 동안 자신의 길을 벗어나지 않으려 고 노력할 것이다. – sehe

+0

이것에 대해서 생각해 보자. 이것은 내 대답에서 기억하려고했던 스펙에서 '것'이었음에 틀림 없다. ... 다시 정류장 주셔서 감사합니다 – sehe

0

당신없이 따라서 발생시키고, 메모리에 동일한 예외 객체를 가리키는 것이다 캐치 블록의 변수, 즉 생성 된 동일한 예외 객체를 얻을 것이다 참조 (& 심볼)를 사용하여 예외를 잡으면 사본 단점이 있어야합니다. 예외로 값을 catch하는 다른 catch 블록을 사용하는 것처럼 컴파일러에서 catch가 발생하는 예외 객체의 복사본을 만들고이 새로운 복사본을 catch 블록의 변수에 할당하려면 코드를 생성해야합니다. 당신은 공공 복사 죄수가 필요합니다.

0

복사 생성자 (및 할당 연산자)를 비공개로 만드는 것은 C++에서 복사를 방지하기 위해 널리 사용되는 기술입니다. 대체로 대다수의 C++ 클래스 (접근 가능한 복사 생성자가 있어야하는 예외는 아님)는 복사가 불가능해야합니다. 저는 거의 모든 클래스가 내 코드에서이 작업을 수행한다는 것을 알고 있습니다.

+0

예외 클래스 (항상 사용됨)는 예외 객체가 항상 표현식을 던지기 위해 피연산자에서 복사 (또는 이동)되기 때문에 개인 복사 생성자를가집니다. –

+0

@Charles ah yes - 예외에 대한 복사 제공자가 "액세스 가능"해야한다는 것을 잊었습니다. 그러나 복사 불가능한 다른 클래스에 대한 요점은 있습니다. –

관련 문제