예외 안전

예비 경고: 예외 안전은 완전한 기능이 아닙니다! 일반적인 경우에는 작동하지만 여전히 클래스가 누수되거나 충돌이 발생할 수 있습니다.

Qt 자체는 예외를 던지지 않습니다. 대신 에러 코드가 사용됩니다. 또한 일부 클래스에는 QIODevice::errorString() 또는 QSqlQuery::lastError()와 같이 사용자가 볼 수 있는 오류 메시지가 있습니다. 예외를 사용하면 라이브러리 크기가 20% 이상 증가할 수 있습니다.

다음 섹션에서는 컴파일 시 예외 지원이 활성화된 경우 Qt의 동작에 대해 설명합니다.

예외 안전 모듈

컨테이너

Qt의 컨테이너 클래스는 일반적으로 예외 중립적입니다. 컨테이너는 내부 상태를 유효하게 유지하면서 포함된 유형 T 내에서 발생하는 모든 예외를 사용자에게 전달합니다.

예제:

QList<QString> list;
...
try {
    list.append("hello");
} catch (...) {
}
// list is safe to use - the exception did not affect it.

이 규칙의 예외는 할당 또는 복사 구조 중에 예외가 발생할 수 있는 유형의 컨테이너입니다. 이러한 유형의 경우 값을 반환할 뿐만 아니라 컨테이너를 수정하는 함수는 사용하기에 안전하지 않습니다:

MyType s = list.takeAt(2);

s 을 할당하는 동안 예외가 발생하면 인덱스 2의 값은 이미 컨테이너에서 제거되었지만 아직 s 에 할당되지 않은 상태입니다. 이 값은 복구할 기회 없이 손실됩니다.

올바른 작성 방법

MyType s = list.at(2);
list.removeAt(2);

할당이 throw되는 경우에도 컨테이너에는 여전히 값이 포함되며 데이터 손실은 발생하지 않습니다.

암시적으로 공유된 Qt 클래스는 할당 연산자나 복사 생성자를 던지지 않으므로 위의 제한이 적용되지 않습니다.

메모리 부족 처리

대부분의 데스크톱 운영 체제는 메모리를 과도하게 커밋합니다. 즉, 할당 시점에 사용 가능한 메모리가 충분하지 않음에도 불구하고 malloc() 또는 operator new 은 유효한 포인터를 반환합니다. 이러한 시스템에서는 std::bad_alloc 유형의 예외가 발생하지 않습니다.

다른 모든 운영 체제에서, Qt는 할당에 실패하면 std::bad_alloc 유형의 예외를 던집니다. 시스템에 메모리가 부족하거나 요청된 크기를 할당할 수 있는 연속 메모리가 충분하지 않은 경우 할당이 실패할 수 있습니다.

이 규칙의 예외는 문서화되어 있습니다. 예를 들어 QImage 생성자는 메모리가 충분하지 않은 경우 예외를 발생시키는 대신 null 이미지를 생성합니다.

예외에서 복구하기

현재 Qt 내에서 발생하는 예외(예: 메모리 부족)로부터 복구하기 위해 지원되는 유일한 사용 사례는 이벤트 루프를 종료하고 애플리케이션을 종료하기 전에 몇 가지 정리를 수행하는 것입니다.

일반적인 사용 사례입니다:

QApplication app(argc, argv);
...
int ret;
try {
    ret = app.exec();
} catch (const std::bad_alloc &) {
    // clean up here, e.g. save the session
    // and close all config files.

    return EXIT_FAILURE; // exit the application
}
...
return ret;

예외가 발생한 후 윈도우 서버에 대한 연결이 이미 닫혀 있을 수 있습니다. 예외를 잡은 후 GUI 관련 함수를 호출하는 것은 안전하지 않습니다.

클라이언트 코드의 예외

신호 및 슬롯

Qt의 신호-슬롯 연결 메커니즘에 의해 호출된 슬롯에서 예외를 던지는 것은 슬롯 내에서 처리되지 않는 한 정의되지 않은 동작으로 간주됩니다:

State state;
StateListener stateListener;

// OK; the exception is handled before it leaves the slot.
QObject::connect(&state, SIGNAL(stateChanged()), &stateListener, SLOT(throwHandledException()));
// Undefined behaviour; upon invocation of the slot, the exception will be propagated to the
// point of emission, unwinding the stack of the Qt code (which is not guaranteed to be exception safe).
QObject::connect(&state, SIGNAL(stateChanged()), &stateListener, SLOT(throwUnhandledException()));

일반 함수 호출처럼 슬롯이 직접 호출된 경우 예외를 사용할 수 있습니다. 이는 슬롯을 직접 호출할 때 연결 메커니즘이 우회되기 때문입니다:

State state; StateListener stateListener;// ...try { // OK; 직접 슬롯을 호출합니다.stateListener.throwException(); } catch (...) {    qDebug() << "Handling exception not caught in slot.";

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.