2011-02-03 3 views
61

클래스 QNetworkReply의 객체가 있습니다. finished() 신호에 연결된 슬롯 (다른 객체에 있음)이 있습니다. 신호는 동기 신호입니다 (기본 신호). 스레드는 하나뿐입니다.delete 및 deleteLater는 Qt의 신호 및 슬롯과 관련하여 어떻게 작동합니까?

어느 순간 어느 순간 나는 두 개체를 모두 없애기를 원합니다. 더 이상 신호 나 그로부터 아무것도. 나는 그들이 사라지길 바란다. 글쎄, 난 내가

delete obj1; delete obj2; 

를 사용합니다 생각하지만 난 정말 할 수 있습니까? ~ QObject를위한 사양 말 : 보류중인 이벤트가 충돌을 일으킬 수 있습니다 전달 될 기다리는 동안

는 QObject를 삭제.

'보류중인 이벤트'는 무엇입니까? 내 delete으로 전화하는 동안 이미 '보류중인 이벤트'가 전달되어 충돌이 발생할 수 있으며 실제로 있는지 확인할 수 없습니까?

그래서 내가 전화를 가정 해 봅시다 :

obj1->deleteLater(); obj2->deleteLater(); 

는 안전을 위해.

하지만 정말 안전합니까? deleteLater은 제어가 도착할 때 주 루프에서 처리 될 이벤트를 추가합니다. 이미 obj1 또는 obj2에 대한 보류중인 이벤트 (신호)가있을 수 있습니까? 으로 처리되기를 기다리고 있습니다. deleteLater가 처리됩니까? 그것은 매우 불행한 일입니다. 나는 약간의 삭제 된 상태에 대한 코드 검사를 쓰고 모든 슬롯에서 들어오는 신호를 무시하고 싶지 않습니다. QObjects 삭제

+3

'obj-> disconnect();처럼 보입니다. obr-> deleteLater();가 올바른 방법입니다. – stach

답변

59

은 일반적으로 안전합니다 (즉, 정상적인 연습에서, 나는 기압 인식하지 오전 병적 인 경우가있을 수 있습니다) 당신은 두 가지 기본 규칙을 따르는 경우 :

  • 가 슬롯에서 개체를 삭제하지 마십시오 또는 메서드는 직접적으로 또는 간접적으로 (동기식 연결 유형 "직접") 신호에 의해 삭제 될 객체로부터 호출됩니다. 예. 만약 당신이 Operation :: finished()와 슬롯 Manager :: operationFinished()를 가진 클래스 Operation을 가지고 있다면, 그 슬롯에서 신호를 내 보낸 연산 객체를 삭제하고 싶지는 않을 것입니다. finished() 신호를 내보내는 메소드는 방출 (예 : 멤버 액세스) 후에 "this"에 계속 액세스 한 다음 잘못된 "this"포인터로 작업 할 수 있습니다.

  • 마찬가지로 개체의 이벤트 처리기에서 동기식으로 호출되는 코드에서 개체를 삭제하지 마십시오. 예 : SomeWidget :: fooEvent() 또는 거기에서 호출하는 메서드/슬롯에서 SomeWidget을 삭제하지 마십시오. 이벤트 시스템은 이미 h 제된 오브젝트 -> 충돌에서 계속 작동합니다.

모두 (포드 멤버 변수를 액세스하는 동안 충돌 같은) 역 추적 보통 이상한 보면 삭제가 여러 단계를 원래 아래로 발생할 수있는 위치를 신호/슬롯 체인 복잡 한, 특히, 추적하기 까다로울 수있다 삭제 된 객체의 신호 또는 이벤트에 의해 시작됩니다.

이러한 사례는 deleteLater()의 가장 일반적인 사용 사례입니다. 컨트롤이 이벤트 루프로 돌아 가기 전에 현재 이벤트를 완료 할 수 있는지 확인한 다음 이벤트를 삭제합니다.또 다른 방법은 대기열에있는 연결/QMetaObject :: invokeMethod (..., Qt :: QueuedConnection)를 사용하여 전체 동작을 연기하는 것이 더 나은 방법이라고 생각합니다.

2

내가 아는 한, 이것은 주로 개체가 다른 스레드에있는 경우 문제가됩니다. 아니면 실제로 신호를 처리하는 동안.

그렇지 않으면 QObject를 삭제하면 먼저 모든 신호와 슬롯을 연결 해제하고 대기중인 모든 이벤트를 제거합니다. disconnect()를 호출하면됩니다.

13

당신은 약이 내용의 Delta Object Rules의를 읽고 질문에 대한 답을 찾을 수 있습니다

신호 안전 (SS).
신호 내에서 이라는 슬롯 내에서 소멸자를 포함하여 개체의 메서드를 호출하는 것이 안전해야합니다.

단편의 핵심

, QObject를 시그널링 동안 삭제 서포트. 을 사용하려면 에 을 삭제 한 후에 해당 객체에 에 액세스하려고 시도하지 말아야합니다. 그러나 대부분의 Qt 개체는 이런 방식으로 작성되지 않으며 중 하나 일 필요는 없습니다. 이러한 이유 때문에 오브젝트를 삭제해야 할 경우 해당 신호 중 하나 인 오브젝트를 삭제해야 할 확률이 '삭제'이기 때문에 항상 이라고 부르는 것이 좋습니다. 애플리케이션을 크래시합니다.

불행히도 '삭제'를 사용해야 할 때 은 항상deleteLater()를 사용해야합니다. 즉, 코드 경로에 신호 소스가 항상 있다는 것은 분명하지 않습니다. 종종 코드 블록을 사용하여 일부 개체는 안전하지만 미래에는 같은 시점에 코드 블록이 호출되기 시작합니다. 신호 소스에서 갑자기 응용 프로그램이 충돌합니다. 이 문제에 대한 유일한 해결책은 입니다. deleteLater()를 항상 사용하고 심지어 한눈에 그것은 불필요한 것으로 보입니다.

일반적으로 나는 모든 Qt는 개발자 델타 개체 규칙 등의 의무 읽기 간주한다. 그것은 훌륭한 독서 재료입니다.

+1

DOR에 대한 링크를 따라 가면 해당 페이지의 링크를 따라 가야합니다. '신호 안전'링크를 클릭하십시오. 링크의 첫 페이지는 문맥 없이는 이해하기 어렵습니다. (Windows에서 PyQt를 사용하여 종료 할 때 충돌을 쫓고 있는데 내 앱은 개체를 삭제하지 않고 DOR에 대한 링크를 통해 통찰력을 얻을 수 있기를 바랍니다.) – bootchk

19

추천 된 문서의 다음 두 줄에 답변이 나와 있습니다. 보류중인 이벤트가 충돌을 일으킬 수 있습니다 전달되기 위해 대기하는 동안 QObject를 삭제 ~QObject에서

,

. 은 현재 실행중인 스레드와 다른 스레드에있는 QObject를 직접 삭제하면 안됩니다. 대신 deleteLater()를 사용하면 보류중인 모든 이벤트가 전달 된 후에 이벤트 루프가 객체를 삭제합니다.

특히 다른 스레드에서 삭제하지 말라고 말합니다. 단일 스레드 응용 프로그램이므로 QObject을 삭제해도 안전합니다.

그렇지 않으면 다중 스레드 환경에서 삭제해야 할 경우 deleteLater()을 사용하면 모든 이벤트의 처리가 완료되면 QObject이 삭제됩니다.

+5

두 번째 시나리오는 어떻게됩니까? deleteLater를 호출 한 후에도 객체의 슬롯을 호출 할 수 있습니까? – stach