이것은 내 샘플 코드입니다.
#include <iostream>
#include <string>
using namespace std;
class MyClass
{
string figName;
public:
MyClass(const string& s)
{
figName = s;
}
const string& getName() const
{
return figName;
}
};
ostream& operator<<(ostream& ausgabe, const MyClass& f)
{
ausgabe << f.getName();
return ausgabe;
}
int main()
{
MyClass f1("Hello");
cout << f1;
return 0;
}
내가 주석 처리 #include <string>
하면 컴파일러 오류가 발생하지 않는 것 같습니다 #include <iostream>
. 내가 만약 “마우스 오른쪽 클릭 -> 정의로 이동” 마이크로 소프트 VS에서 그들이에서 같은 줄에 두 점 xstring
파일 :
typedef basic_string<char, char_traits<char>, allocator<char> >
string;
하지만 프로그램을 실행할 때 예외 오류가 발생합니다.
OperatorString.exe의 0x77846B6E (ntdll.dll) : 0xC00000FD : 스택 오버플로 (매개 변수 : 0x00000001, 0x01202FC4)
주석 처리 할 때 런타임 오류가 발생하는 이유는 #include <string>
무엇입니까? VS 2013 Express를 사용하고 있습니다.
답변
사실, 매우 흥미로운 행동입니다.
주석 처리 할 때 런타임 오류가 발생하는 이유
#include <string>
그렇게하지 않으면 때문에 MS VC ++ 컴파일러로 오류가 발생 #include <string>
하면하지 않습니다 operator<<
에 대해 정의 std::string
.
컴파일러가 시도 할 때 컴파일 ausgabe << f.getName();
그것이 찾습니다 operator<<
정의 std::string
. 정의되지 않았기 때문에 컴파일러는 대안을 찾습니다. 에 대한 operator<<
정의가 있습니다.MyClass
있고 컴파일러가 그것을 사용하려고 시도하고 그것을 사용하려면 변환 std::string
해야 MyClass
하며 이것은 비명 MyClass
시적 생성자를 가지고 있기 때문에 정확히 발생합니다 ! 따라서 컴파일러는 결국 새 인스턴스를 만들고 MyClass
출력 스트림으로 다시 스트리밍하려고합니다. 결과적으로 끝없는 재귀가 발생합니다.
start:
operator<<(MyClass) ->
MyClass::MyClass(MyClass::getName()) ->
operator<<(MyClass) -> ... goto start;
오류를 방지하려면 #include <string>
대해 operator<<
정의되어 있는지 확인해야합니다 std::string
. 또한 MyClass
이러한 종류의 예기치 않은 변환을 방지하려면 생성자를 명시 적으로 만들어야합니다 . 지혜의 법칙 : 암시 적 변환을 피하기 위해 하나의 인수 만 사용하는 경우 생성자를 명시 적으로 만듭니다.
class MyClass
{
string figName;
public:
explicit MyClass(const string& s) // <<-- avoid implicit conversion
{
figName = s;
}
const string& getName() const
{
return figName;
}
};
operator<<
for std::string
gets <string>
가 포함 된 경우 (MS 컴파일러 포함) 에만 정의되는 것처럼 보이며 이러한 이유로 모든 것이 컴파일되지만 예상치 못한 동작이 발생합니다.operator<<
재귀 적 호출지고 MyClass
대신 호출 operator<<
에 대한을 std::string
.
그것은 through
#include <iostream>
string이 부분적으로 만 포함 된다는 것을 의미합니까 ?
아니요, 문자열은 완전히 포함되어 있습니다. 그렇지 않으면 사용할 수 없습니다.
답변
문제는 코드가 무한 재귀를 수행한다는 것입니다. std::string
( std::ostream& operator<<(std::ostream&, const std::string&)
)에 대한 스트리밍 연산자 는 <string>
헤더 파일에 선언되어 있지만 std::string
자체가 다른 헤더 파일 ( <iostream>
및 모두에 포함됨)에 선언되어 <string>
있습니다.
포함하지 않으면 <string>
컴파일러는 ausgabe << f.getName();
.
에 대한 스트리밍 연산자 MyClass
와를 허용하는 생성자를 모두 정의 std::string
했으므로 컴파일러가이를 사용하여 ( 암시 적 생성을 통해 ) 재귀 호출을 생성합니다.
explicit
생성자 ( explicit MyClass(const std::string& s)
)를 선언하면를 사용 하여 스트리밍 연산자를 호출 할 방법이 없으므로 코드가 더 이상 컴파일되지 않으며 헤더 std::string
를 포함해야합니다 <string>
.
편집하다
내 테스트 환경은 VS 2010이며 경고 수준 1 ( /W1
) 부터 문제에 대해 경고합니다.
경고 C4717 : ‘operator <<‘: 모든 제어 경로에서 재귀 적이며 함수로 인해 런타임 스택 오버플로가 발생합니다.