문제

C++로 DLL을 작성하고 중요한 소멸자를 사용하여 클래스의 전역 개체를 선언한다고 가정해 보겠습니다.DLL이 언로드될 때 소멸자가 호출됩니까?

도움이 되었습니까?

해결책

Windows C++ DLL에서는 모든 전역 개체(클래스의 정적 멤버 포함)가 DLL_PROCESS_ATTACH를 사용하여 DllMain을 호출하기 직전에 생성되며 DLL_PROCESS_DETACH를 사용하여 DllMain을 호출한 직후에 삭제됩니다.

이제 세 가지 문제를 고려해야 합니다.

0 - 물론 전역 비 const 객체는 악합니다(그러나 이미 알고 있으므로 멀티스레딩, 잠금, God-객체 등은 언급하지 않겠습니다).

1 - 객체 또는 다양한 컴파일 단위의 구성 순서(예:CPP 파일)이 보장되지 않으므로 두 개체가 두 개의 서로 다른 CPP에서 인스턴스화되는 경우 개체 A가 B보다 먼저 생성되기를 바랄 수 없습니다.B가 A에 의존하는 경우 이는 중요합니다.해결책은 동일한 컴파일 단위 내에서 모든 전역 객체를 동일한 CPP 파일로 이동하는 것입니다. 객체의 인스턴스화 순서는 생성 순서(파괴 순서의 반대)입니다.

2 - DllMain에서는 금지된 작업이 있습니다.이러한 것들은 아마도 생성자에서도 금지되어 있을 것입니다.그러므로 무언가를 잠그지 마십시오.이 주제에 대한 Raymond Chen의 훌륭한 블로그를 참조하십시오.

http://blogs.msdn.com/oldnewthing/archive/2004/01/27/63401.aspx

http://blogs.msdn.com/oldnewthing/archive/2004/01/28/63880.aspx

이 경우 지연 초기화가 흥미로울 수 있습니다.클래스는 메서드 중 하나를 호출할 때까지 "초기화되지 않은" 상태(내부 포인터는 NULL, 부울은 false 등)로 유지되며, 호출되면 자체적으로 초기화됩니다.기본(또는 기본 하위 함수 중 하나) 내부에서 해당 개체를 사용하는 경우 DllMain 실행 후에 호출되므로 문제가 없습니다.

3 - 물론 DLL A의 일부 전역 개체가 DLL B의 전역 개체에 의존하는 경우 DLL 로드 순서와 종속성에 매우 주의해야 합니다.이 경우 직접 또는 간접적인 순환 종속성을 갖는 DLL은 엄청난 두통을 유발할 것입니다.가장 좋은 해결책은 순환 종속성을 깨는 것입니다.

추신.:C++에서는 생성자가 발생할 수 있으며 DLL 로드 중에 예외가 발생하는 것을 원하지 않으므로 전역 개체가 매우 타당한 이유 없이 예외를 사용하지 않도록 해야 합니다.올바르게 작성된 소멸자는 throw할 권한이 없으므로 이 경우 DLL 언로드는 괜찮습니다.

다른 팁

Microsoft의 이 페이지에서는 DLL 초기화 및 전역 삭제에 대해 자세히 설명합니다.
http://msdn.microsoft.com/en-us/library/988ye33t.aspx

.dll을 연결할 때 실행되는 실제 코드를 보려면 다음을 살펴보세요. %ProgramFiles%\Visual Studio 8\vc\crt\src\dllcrt0.c.

검사에서 소멸자는 다음을 통해 호출됩니다. _cexit() dll CRT에 의해 유지되는 내부 참조 횟수가 0에 도달할 때.

애플리케이션이 종료되거나 DLL이 언로드될 때(둘 중 먼저 발생하는 시점) 호출되어야 합니다.이는 컴파일하는 실제 런타임에 따라 다소 달라집니다.

또한 타이밍과 순서 문제가 모두 있으므로 중요하지 않은 소멸자를 조심하세요.DLL이 언로드될 수 있습니다. ~ 후에 소멸자가 의존하는 DLL로 인해 분명히 문제가 발생할 수 있습니다.

fdwReason = DLL_PROCESS_DETACH 매개변수를 사용하여 DllMain이 호출되면 응용 프로그램에서 DLL이 언로드된다는 의미입니다.전역/정적 객체의 소멸자가 호출되기 전의 시간입니다.

확장자가 *.exe인 Windows 바이너리 이미지 파일에는 *.dll이 있습니다. PE 형식이러한 파일에는 진입점이 있습니다.다음과 같은 dumpbin 도구를 사용하여 볼 수 있습니다.

dumpbin /headers dllname.dll

Microsoft에서 C 런타임을 사용하는 경우 입력 지점은 *crtstartup 또는 *dllmaincrtstartup과 같은 것입니다.

이러한 함수는 c 및 C++ 런타임의 초기화를 수행하고 각각 (main, WinMain) 또는 DllMain에 실행을 위임합니다.

Microsoft의 VC 컴파일러를 사용하는 경우 VC 디렉터리에서 이 함수의 소스 코드를 볼 수 있습니다.

  • crt0.c
  • dllcrt0.c

DllMainCRTStartup은 dll 언로드 중에 알림 DLL_PROCESS_DETACH를 검색할 때 일반 시나리오의 .data 섹션에서 전역 변수를 초기화/초기화하는 데 필요한 모든 것을 처리합니다.예를 들어:

  • 프로그램 시작 스레드의 main 또는 WinMain이 제어 흐름을 반환합니다.
  • 명시적으로 FreeLibrary를 호출하고 use-dll-counter가 0입니다.
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top