2010-01-07 2 views
3

동료 중 일부가 오늘 C++ 코드에 문제가있었습니다. 그는 객체의 가상 메소드의 이상한 행동을 디버깅하고있었습니다. 메서드가 실행될 때마다 (디버그, Visual Studio 2005), 모든 것이 잘못되어 디버거가 해당 메서드에서 처리하지 않지만 개체의 소멸자에서 처리합니다. 또한 객체의 가상 테이블은 소멸자 만 나열하고 다른 방법은 없습니다.가상 메서드 혼란, 어떻게 그 원인을 찾을 수 있습니까?

이전에이 동작을 보지 못했으며 런타임 오류가 인쇄되어 ESP 레지스터에 대해 뭔가를 말했습니다. 나는 당신에게 올바른 오류 메시지를 줄 수 있었으면 좋겠지 만 지금은 정확하게 기억하지 못합니다.

어쨌든 혹시 혹시 혹시 혹시 혹시 본 적이 있으십니까? 무엇이 그러한 행동을 일으킬 수 있습니까? 어떻게 고정 될까요? 우리는 여러 번 프로젝트를 재구성하려고 시도했지만 IDE를 다시 시작한 것은 아무 것도 도움이되지 않았습니다. 또한 메모리가 양호한 상태인지 확인하기 위해 메서드 호출 전에 _CrtCheckMemory 함수를 사용했으며 true (이는 의미)을 반환했습니다. 나는 더 이상 아이디어가 없다. 너?

+0

printf("%d"); 같은 라인

  • 있습니까? – Seth

  • +0

    아이디어가 있었지만 더 이상 올바르게 기억하지 못합니다. 인간의 기억에만 Windows 클립 보드와 같은 것이 있으면 나중에 사용하기 위해 사물을 쉽게 복사 할 수 있습니다. –

    +0

    이것이 범인이라고는 생각되지 않습니다.하지만 어쨌든 생성자/소멸자의 가상 메서드를 호출하지 않았는지 확인하십시오 – Danra

    답변

    2

    이전에 본 적이 있습니다. 일반적으로 디버그 모드에있는 동안 릴리스 빌드 .LIB 파일에서 클래스를 사용하기 때문에 발생합니다. 다른 누군가가 더 좋은 예를 보았을 것입니다. 그리고 저는 대답에 대한 답을 얻을 것입니다.

    +0

    이것이 사실 인 지 잘 모르겠습니다. 디버그 모드에서 모든 것을 다시 빌드했습니다. – Geo

    +0

    컴퓨터를 재부팅하고 깨끗하게 재구성합니까? – wheaties

    +0

    나는 그것을 아침에 시험 할 것이다. – Geo

    1

    아마 static_cast<>이 필요한 C 스타일의 캐스트를 사용하고 있을까요? 이것은 다중 상속이 관여 할 때마다 당신이보고 오류의 종류, 예를 들면 발생할 수 있습니다 :

    class Base1 {}; 
    class Base2 {}; 
    class Derived : public Base1, public Base2 {}; 
    
    Derived *d = new Derived; 
    Base2* b2_1 = (Base2*)d; // wrong! 
    Base2* b2_2 = static_cast<Base2*>(d); // correct 
    assert(b2_1 == b2_2); // assertion may fail, because b2_1 != b2_2 
    

    , 이것은 항상 그런 것은하지 않을 수 있습니다, 이것은 (컴파일러와 관련된 모든 클래스의 선언에 따라 달라집니다 아마도 모든 클래스가 가상 메소드를 가지고있을 때 발생하지만 정확한 규칙은 없습니다.)

    OR : 코드의 완전히 다른 부분이 메모리를 덮어 쓰고 있습니다. 오류를 격리하고 오류가 계속 발생하는지 확인하십시오. CrtCheckMemory은 메모리를 덮어 쓰는 경우가 적습니다 (예 : 특별히 표시된 힙 관리 위치에 쓸 때).

    +0

    글쎄요, C 스타일의 캐스트보다'static_cast '를 사용하는 것이 좋습니다. 그러나 코드에서 본질적으로 C 스타일의 캐스트에는 문제가 없습니다. 상속을 잘 처리 할 수 ​​있습니다. – sbk

    +0

    아니요, C 스타일의 캐스트가 잘못되었습니다. 자세한 설명은 다음과 같습니다. http://en.wikipedia.org/wiki/Virtual_method_table#Multiple_inheritance_and_thunks - 흥미롭게도 우연히도이 예는 mine =과 유사합니다. – Frunsi

    +0

    글쎄, 적어도 VS2008 컴파일러는 포인터를 수정하지 않았습니다. 위키피디아의 또 다른 기사에서 C 스타일의 캐스트가 이렇게해야한다고 제안 했음에도 불구하고 http://en.wikipedia.org/wiki/Thunk#Thunks_in_object-oriented_programming - Wikipedia가 잘못되었거나 VS2008 컴파일러의 버그입니다. . – Frunsi

    1

    잘못된 매개 변수 개수로 함수를 호출하면 쉽게 스택을 파기하고 정의되지 않은 동작을 일으킬 수 있습니다. MFC를 사용할 때 특정 오류가 쉽게 발생할 수 있습니다. 예를 들어 디스패치 매크로를 사용하여 올바른 숫자 또는 매개 변수 유형이없는 메서드에서 메시지를 가리키는 경우 (예 : 해당 함수가 포인터는 유형에 대해 강하게 검사되지 않습니다). 마지막으로 그 특별한 문제에 직면 한 지 10 년이 지났기 때문에 내 기억이 흐릿합니다.

    +0

    +1은 매개 변수 개수가 일치하지 않을 때 MFC의 이상한 동작을 언급합니다. –

    1

    함수 호출을 통해 ESP 값이 제대로 저장되지 않았습니다.

    이러한 종류의 동작은 일반적으로 문제의 특정 클래스를 만든 코드와 다른 클래스 또는 함수 정의로 컴파일 된 호출 코드를 나타냅니다.

    새로 빌드 된 대신로드되는 구성 요소 dll의 다른 버전이있을 수 있습니까? 이는 빌드 후 단계의 일부로 항목을 복사하거나 LoadLibrary 또는 이와 동등한 작업을 수행하기 전에 프로세스가 다른 디렉토리에서 실행되거나 dll 검색 경로를 변경하는 경우에 발생할 수 있습니다.

    클래스 정의가 변경되어 가상 함수의 서명을 추가, 제거 또는 변경 한 다음 증분 빌드가 완료되고 다시 컴파일해야하는 모든 코드가 아닌 복잡한 프로젝트에서 자주 발생했습니다 실제로 다시 컴파일됩니다.이론적으로 프로그램의 일부가 vptr 또는 vtable을 일부 다형성 객체를 덮어 쓰는 경우 발생할 수 있지만 항상 나쁜 부분 빌드가 훨씬 더 많은 원인이된다는 것을 발견했습니다.

    개발자가 의도적으로 다른 사용자가 다시 빌드해야하는 경우에만 컴파일러에게 컴파일러에게 알리거나 종속성이 올바르게 설정되지 않은 솔루션에 여러 솔루션 또는 여러 프로젝트가있을 수 있습니다.

    Visual Studio는 솔루션의 프로젝트가 올바르게 링크되어 있어도 생성 된 종속성을 수정하지 못하는 경우가 있습니다. 이것은 비주얼 스튜디오가 비난하는 것보다 덜 자주 발생합니다.

    중간 빌드 파일을 모두 제거하고 을 모두 다시 빌드하면 소스에서 일반적으로이 문제를 해결합니다. 분명히 매우 큰 프로젝트의 경우 이것은 심각한 벌칙이 될 수 있습니다. 어쨌든 추측-축제를 이래로

    1

    , 나를 여기에서 하나 :

    당신은 엉망 스택

    _CrtCheckMemory을 그 확인하지 않습니다. 스택이 손상되는 이유에 :

    • 좋은 오래된 스택 오버 플로우 이미 WinAPI를 함수에 잘못된 호출 규칙에 콜백을 전달처럼, 나도 몰라 (언급 한 규칙의 불일치를 호출
    • ; 무엇 정적 또는 동적 라이브러리는 당신과 연결되어?) 여러 스레드가 참여
    관련 문제