Qt의 신호 및 슬롯과 관련하여 delete 및 deleteLater가 어떻게 작동합니까?
QNetworkReply 클래스의 객체가 있습니다. finished () 신호에 연결된 슬롯 (다른 객체에 있음)이 있습니다. 신호는 동기식입니다 (기본 신호). 스레드는 하나뿐입니다.
언젠가는 두 개체를 모두 제거하고 싶습니다. 더 이상 신호 나 그 어떤 것도 없습니다. 나는 그들이 사라지기를 바랍니다. 글쎄, 나는 사용할 것이라고 생각했다.
delete obj1; delete obj2;
하지만 정말 할 수 있습니까? ~ QObject의 사양은 다음과 같습니다.
보류중인 이벤트가 전달되기를 기다리는 동안 QObject를 삭제하면 충돌이 발생할 수 있습니다.
'보류중인 이벤트'란 무엇입니까? 내를 호출하는 동안 delete
이미 전달 될 '보류중인 이벤트'가 몇 개 있고 충돌을 일으킬 수 있으며 실제로 있는지 확인할 수 없다는 의미 일 수 있습니까?
그래서 내가 전화한다고 가정 해 봅시다.
obj1->deleteLater(); obj2->deleteLater();
안전하다.
하지만 정말 안전한가요? 는 deleteLater
제어가 오면 메인 루프에서 처리되는 이벤트를 추가합니다. deleteLater가 처리 되기 전에 메인 루프에서 처리되기를 기다리고 obj1
있거나 obj2
이미 거기에 보류중인 이벤트 (신호) 가있을 수 있습니까? 그것은 매우 불행 할 것입니다. '약간 삭제됨'상태를 확인하고 모든 슬롯에서 들어오는 신호를 무시하는 코드를 작성하고 싶지 않습니다.
두 가지 기본 규칙을 따르는 경우 QObjects를 삭제하는 것은 일반적으로 안전합니다 (예 : 정상적인 실무에서는 atm에 대해 알지 못하는 병리학적인 경우가있을 수 있음).
삭제할 개체에서 직접 또는 간접적으로 (동기 연결 유형 "직접") 신호로 호출되는 슬롯 또는 메서드의 개체를 삭제하지 마십시오. 예를 들어 Operation :: finished () 시그널과 Manager :: operationFinished () 시그널이있는 Operation 클래스가있는 경우 해당 슬롯에서 시그널을 방출 한 operation 객체를 삭제하고 싶지 않습니다. finished () 신호를 방출하는 메소드는 방출 후에 "this"에 계속 액세스 할 수 있으며 (예 : 멤버 액세스) 유효하지 않은 "this"포인터에서 작동합니다.
마찬가지로 개체의 이벤트 처리기에서 동 기적으로 호출되는 코드의 개체를 삭제하지 마십시오. 예를 들어 SomeWidget :: fooEvent () 또는 거기에서 호출하는 메서드 / 슬롯에서 SomeWidget을 삭제하지 마십시오. 이벤트 시스템은 이미 삭제 된 개체-> 충돌에서 계속 작동합니다.
역 추적이 일반적으로 이상하게 보이므로 (POD 멤버 변수에 액세스하는 동안 충돌과 같이), 특히 삭제가 원래 신호 또는 이벤트에 의해 시작된 여러 단계 아래로 발생할 수있는 복잡한 신호 / 슬롯 체인이있는 경우 둘 다 추적하기가 까다로울 수 있습니다. 삭제 된 개체입니다.
이러한 경우는 deleteLater ()의 가장 일반적인 사용 사례입니다. 컨트롤이 이벤트 루프로 돌아 가기 전에 현재 이벤트가 완료 될 수 있는지 확인한 다음 개체를 삭제합니다. 또 다른 방법은 대기중인 연결 / QMetaObject :: invokeMethod (..., Qt :: QueuedConnection)를 사용하여 전체 작업을 연기하는 것입니다.
추천 된 문서의 다음 두 줄에 답이 나와 있습니다.
에서 ~ QObject를 ,
보류중인 이벤트가 전달되기를 기다리는 동안 QObject를 삭제하면 충돌이 발생할 수 있습니다. 당신 이 현재 실행 스레드와 다른 스레드에있는 경우 직접 QObject를 삭제하지 않아야합니다. 대신 deleteLater ()를 사용하면 보류중인 모든 이벤트가 전달 된 후 이벤트 루프가 객체를 삭제합니다.
다른 스레드에서 삭제하지 말라고 구체적으로 말합니다. 단일 스레드 응용 프로그램이 있으므로 QObject
.
그렇지 않으면 다중 스레드 환경에서 삭제해야하는 경우 모든 이벤트 처리가 완료되면 deleteLater()
삭제 QObject
됩니다.
다음과 같은 델타 개체 규칙 중 하나에 대한 질문에 대한 답변을 찾을 수 있습니다 .
신호 안전 (SS).
신호 중 하나에 의해 호출되는 슬롯 내에서 소멸자를 포함하여 객체의 메서드를 호출하는 것이 안전해야합니다.
파편:
핵심에서 QObject는 신호를 보내는 동안 삭제되는 것을 지원합니다. 이를 활용하려면 개체가 삭제 된 후 자신의 구성원에 액세스하지 않도록해야합니다. 그러나 대부분의 Qt 객체는 이러한 방식으로 작성되지 않으며 둘 중 하나에 대한 요구 사항도 없습니다. 이러한 이유로 신호 중 하나에서 객체를 삭제해야하는 경우 항상 deleteLater ()를 호출하는 것이 좋습니다. '삭제'가 응용 프로그램을 중단시킬 가능성이 있기 때문입니다.
불행히도 언제 'delete'와 deleteLater ()를 사용해야하는지는 분명하지 않습니다. 즉, 코드 경로에 신호 소스가 있다는 것이 항상 분명하지는 않습니다. 종종 현재 안전한 일부 객체에 '삭제'를 사용하는 코드 블록이있을 수 있지만, 미래의 어느 시점에서이 동일한 코드 블록이 신호 소스에서 호출되고 이제 갑자기 애플리케이션이 충돌합니다. 이 문제에 대한 유일한 일반적인 해결책은 한 눈에 불필요하게 보일지라도 항상 deleteLater ()를 사용하는 것입니다.
일반적으로 나는 Delta Object Rules 를 모든 Qt 개발자가 읽어야 할 의무 라고 생각 합니다. 훌륭한 읽기 자료입니다.
내가 아는 한, 이것은 객체가 다른 스레드에 존재하는 경우 주로 문제입니다. 또는 실제로 신호를 처리하는 동안 일 수도 있습니다.
그렇지 않으면 QObject를 삭제하면 먼저 모든 신호와 슬롯의 연결이 끊어지고 보류중인 모든 이벤트가 제거됩니다. disconnect () 호출로 할 수 있습니다.
'developer tip' 카테고리의 다른 글
이동 된 파일의 GIT 이력보기 (0) | 2020.10.27 |
---|---|
Android의 스레딩 예제 (0) | 2020.10.27 |
정적 const int에 대한 정의되지 않은 참조 (0) | 2020.10.27 |
STA 스레드를 실행하는 작업 (TPL)을 만드는 방법은 무엇입니까? (0) | 2020.10.27 |
PowerShell Set-Content 및 Out-File-차이점은 무엇입니까? (0) | 2020.10.27 |