한국어
Qt
 

clang이 Qt 코드를 이해할 수 있게 해주는 clazy를 사용하여 컴파일 타임에 Signal / Slot 연결에 관한 13가지 자주하는 실수와 실수를 고치는 올바른 방법을 알아본다.

clazy는 Linux, macOS 및 Windows/MSVC에서 사용가능하다. 대부분의 Linux 배포판은 QtCreator와 함께 번들로 clazy를 제공하거나 직접 설치할 수 있다. https://github.com/KDE/clazy

1. connect-non-signal

이 검사는 시그널이 아닌 것을 무언가에 연결할 때 경고한다. 예를 들어 두 개의 슬롯을 함께 연결하는 경우:

connect(obj, &MyObj::mySlot, &MyObj::mySlot2);
warning: MyObj::mySlot is not a signal [-Wclazy-connect-non-signal]

유효한 C++ 코드이므로 잘 컴파일된다. 그러나 connect 는 적어도 1개의 시그널을 참조해야 하므로 위의 내용은 의미가 없다. clazy를 사용하면 컴파일러가 Qt 의미를 알고 이 실수에 대해 경고한다.

2. lambda-in-connect

connect() 내부의 lambda가 참조로 지역 변수를 캡처할 때 경고한다.

Example:

void myFunction()
{
    int localVar = ...;
 
    // program will crash when signal is emitted!
    connect(m_object, &MyObj::mySignal, [&localVar] { ... }); 
}

캡처된 변수가 범위를 벗어난 후에 람다가 호출될 수 있으므로 일반적으로 충돌이 발생한다.

3. connect-3arg-lambda

람다를 사용하는 3개의 인수 connect()를 사용할 때 경고한다. 연결 수명을 제어하기 위해 컨텍스트 개체를 사용하여 4개의 인수가 있는 오버로드를 사용하는 것이 좋다.

람다를 사용하여 여러 인수가 있는 슬롯에 시그널을 연결하는 것은 매우 일반적이다.

connect(m_widget, &MyWidget::textChanged, [this] (const QString &text) {
    m_receiver->update(text, false);
});

그러나 위의 코드는 m_receiver가 삭제된 후 시그널이 방출되면 충돌을 일으킨다. 이것을 피하려면 컨텍스트 객체를 세 번째 인수로 전달해야한다.

connect(m_widget, &MyWidget::textChanged, m_receiver,
        [this] (const QString &text) { (....) });

4. lambda-unique-connection

리시버(Receiver)가 functor, lambda 또는 global functionQt::UniqueConnection로 사용한 경우. Qt 문서에 명시된 바와 같이 이 connect() 오버로드 중 Qt::UniqueConnection는 멤버 함수에 연결하는 경우에만 적용된다.

5. thread-with-slots

QThread 파생 클래스에 있는 모든 슬롯에 대해 경고한다. 반드시 버그는 아니지만, 이러한 슬롯은 스레드 자체가 아니라 QThread QObject가 있는 스레드에서 실행되기 때문에 안전하지 않다. 모범 사례는 일반적으로 여기에 설명된 대로 worker 개체를 사용하는 것이다.

6. old-style-connect

오래된 SIGNAL()/SLOT() 구문을 사용하는 connect() 문을 경고한다. 멤버에 대한 포인터 구문을 사용하면 런타임이 아닌 컴파일 타임에 오류를 잡을 수 있다. 새 양식에 대한 연결을 자동으로 다시 작성하기 위한 수정 사항이 포함되어 있다.

7. connect-not-normalized

SIGNAL(), SLOT(), Q_ARG()Q_RETURN_ARG()의 내용이 정규화되지 않은 경우 경고한다. 정규화된 구문을 사용하면 불필요한 메모리 할당을 방지할 수 있다.

Example:

// warning: Signature is not normalized. Use void mySlot(int) instead of void mySlot(const int) [-Wclazy-connect-not-normalized]
o.connect(&o, SIGNAL(mySignal(int, int)),
          &o, SLOT(void mySlot(const int)));

8. overridden-signal

파생 클래스에서 시그널을 재정의할 때 경고한다. 재정의된 시그널이 있는 API는 사용하기 어렵고 예상치 못한 버그가 발생하기 쉽다. 설상가상으로 Qt는 시그널을 비시그널로 또는 그 반대로 무시할 수도 있다.

두 시그널의 서명이 다를 때 경고하지 않는다.

9. virtual-signal

이 검사는 signalvirtual일 때 경고한다. 가상 시그널은 예상치 못한 것이므로 connect() 문을 읽기 어렵게 만든다. 또한 런타임에 다음과 같은 메시지를 출력하여 사용을 권장하지 않는다:
Warning: Signals cannot be declared virtual

10. const-signal-or-slot

signal 또는 non-void slot이 const일 때 경고한다.

이는 의도하지 않게 getter 를 슬롯으로 표시하거나 잘못된 방법에 연결하는 것을 방지하기 위한 것이다. 시그널의의 경우 const로 표시하는 것은 무의미하다.

다음과 같은 경우에 경고한다.

  • 슬롯으로 표시된 non-void const 메서드
  • 시그널로 표시된 const 메서드
  • 슬롯으로 표시되지 않은 메서드에 연결

QML에 메소드를 노출하려면 Q_PROPERTY 또는 Q_INVOKABLE을 권장한다.

11. incorrect-emit

가독성을 위해 시그널을 호출할 때 항상 emit(또는 Q_EMIT)을 사용해야 한다. 반대로 시그널이 아닌 다른 것을 호출할 때 이러한 매크로를 사용하면 안 된다. emit(또는 Q_EMIT)을 사용하는 것을 잊었거나 사용하지 않아야 할 때도 Clazy가 경고한다.

12. connect-by-name

auto-connection 슬롯이 사용될 때 경고한다. 더 이상 사용해서는 안 되는 오래되고 인기 없는 기능인 "이름으로 연결"이라고도 한다. 이러한 유형의 연결은 간단한 개체 이름 변경으로도 코드가 손상될 수 있으므로 매우 취약하다.

이 검사는 단순히 on_*_*과 같은 이름의 슬롯에 대해 경고한다. .ui 파일을 사용하지 않더라도 이 이름은 오해의 소지가 있고 가독성이 좋지 않기 때문이다.

한편 Qt 5에서 멤버 함수에 대한 포인터 연결 구문은 컴파일 타임에 오류를 포착하므로 선호된다.

13. qproperty-without-notify

CONSTANT Q_PROPERTYNOTIFY 시그널이 없을 때 경고한다. 이 사례는 실제로 모든 Q_PROPERTY에 유용하다. 속성 클라이언트가 알림을 사용할 수 있기 때문이다.

 

Qt, 더 구체적으로 moc는 기술적인 한계로 인해 또는 단순히 소스 호환성을 유지하기 위한 요구사항으로 인해 몇몇 사항에 대해 매우 관대하다. 우리가 이 지침을 따르고 clang용 오픈 소스 플러그인인 clazy를 활용함으로써 더 엄격하고 허용되는 것의 하위 집합만 사용해야 한다고 생각한다. clazy가 보고한 일부 문제는 코드의 버그를 의미하지 않지만 그럼에도 불구하고 경고가 0이 되도록 노력해야 한다.

번호 제목 글쓴이 날짜 조회 수
공지 Qt프로그래밍(QtQuick) Beginner를 위한 글 읽는 순서 운영자 2019.01.05 91658
40 Qt 응용프로그램에서 Lottie Animation사용 file makersweb 2021.05.30 1613
39 앱을 종료할 때 QML 바인딩 오류를 피하는 방법 makersweb 2021.08.08 1247
38 QML 에서 QR코드 생성 file makersweb 2021.08.20 1456
37 QML 코딩 규칙 makersweb 2021.09.05 4355
36 QML에서 Websocket 서버와 통신 file makersweb 2021.09.18 1570
35 Qt 응용프로그램에서 PDF 문서 렌더링 file makersweb 2021.09.23 1422
34 안드로이드용 Qt 6.2 makersweb 2021.10.02 1259
33 QML에서 앵커(anchors)로 위치 지정 file makersweb 2021.10.05 5163
32 Qt 6의 C++ 프로퍼티 바인딩 예제 makersweb 2021.11.01 1422
31 Qt Android 앱에 AdMob 배너달기 file makersweb 2021.12.04 1005
30 Qt Bluetooth Low Energy 개요 makersweb 2022.02.13 1387
29 Binding 타입으로 객체 속성 간 묶기 makersweb 2022.03.04 1060
28 성능 고려 및 제안 사항 makersweb 2022.03.07 1152
27 VirtualKeyboard 스타일 커스터 마이징 makersweb 2022.03.13 1303
26 Qt로 작성된 iOS 앱에서 시리얼 통신 file makersweb 2022.04.30 1773
25 단일 인스턴스 Qt 응용 프로그램(Single-instance Application) makersweb 2022.06.23 1404
24 HTTPS URL을 연결할 때 SslHandshakeFailedError 오류 makersweb 2022.07.31 1039
23 Qt 6.4에 추가될 Qt Quick 3D Physics file makersweb 2022.08.07 1030
22 Qt 스마트 포인터 (QSharedPointer, QScopedPointer, QPointer) makersweb 2022.08.18 2037
» clazy 로 13개의 시그널, 슬롯 오류 해결 makersweb 2022.08.23 1448