한국어
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 85850
178 가상키보드(Qt Virtual Keyboard)를 사용하는 방법 [32] file makersweb 2019.05.03 220982
177 콘솔에서 사용자 입력받기 file makersweb 2020.03.22 51844
176 QString 문자열 다루기 예제 운영자 2019.01.26 40048
175 Windows에서 Qt 설치 따라하기 file makersweb 2019.10.14 30870
174 Qt의 시그널 슬롯 시스템 file makersweb 2015.10.20 23578
173 QThread 소개 및 예제 makersweb 2019.12.25 19440
172 QtCreator Design으로 GUI만들기 (QML로 만드는 Hello World -2) [1] file makersweb 2019.05.26 14867
171 초보자를 위한 첫번째 프로젝트 - QML로 만드는 Hello World file makersweb 2018.03.16 14446
170 Qt 프로그래밍의 시작 makersweb 2015.10.25 14364
169 Qml과 C++로 구현하는 GUI어플리케이션 file makersweb 2018.12.25 13936
168 QML과 QtQuick 모듈 개념과 기본 타입들 makersweb 2019.04.26 13388
167 Windows에서 라즈베리파이3용 Qt5.10.0 크로스컴파일 [20] file makersweb 2018.02.23 12921
166 Qt의 오픈소스 라이센스 소개 file makersweb 2019.12.15 12549
165 Qml 기본 컴포넌트 강좌 (1) file makersweb 2019.01.03 12059
164 QtSerialPort를 사용한 시리얼(Serial)통신 [3] makersweb 2019.05.21 11890
163 Qt Installer Framework - 패키징, 설치프로그램 제작 file makersweb 2018.10.14 11662
162 Qt 응용프로그램 배포(windows) file makersweb 2018.10.10 11310
161 Ubuntu Linux에서 Qt Creator 설치 file makersweb 2016.03.06 10667
160 Qt의 스레드간 시그널 슬롯의 커넥션타입 [1] makersweb 2015.10.24 10167
159 Qt애플리케이션 객체(QCoreApplication, QGuiApplication, QApplication) 에 대해서 makersweb 2019.11.11 10088