diff --git a/README.md b/README.md index 084d637..ebb4a16 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ This is a Claude Code skill designed to help developers conduct effective code r | **Go** | Error handling, goroutines/channels, context propagation, interface design, testing patterns | | **C** | Pointer safety, UB pitfalls, resource management, error handling | | **C++** | RAII, ownership, move semantics, exception safety, performance | +| **Qt** | Object model, Signals/Slots, memory management (parent/child), thread safety, GUI performance | | **CSS/Less/Sass** | CSS variables, !important usage, performance optimization, responsive design, browser compatibility | | **TanStack Query** | v5 best practices, queryOptions, useSuspenseQuery, optimistic updates | | **Architecture** | SOLID principles, anti-patterns, coupling/cohesion, layered architecture | @@ -53,6 +54,7 @@ This is a Claude Code skill designed to help developers conduct effective code r | **reference/go.md** | ~990 | Go goroutines/channels/context/interfaces (on-demand) | | **reference/c.md** | ~210 | C memory safety/UB/error handling (on-demand) | | **reference/cpp.md** | ~300 | C++ RAII/lifetime/move semantics (on-demand) | +| **reference/qt.md** | ~190 | Qt object model/signals-slots/GUI performance (on-demand) | | **reference/css-less-sass.md** | ~660 | CSS/Less/Sass variables/performance/responsive (on-demand) | | **reference/architecture-review-guide.md** | ~470 | SOLID/anti-patterns/coupling analysis (on-demand) | | **reference/performance-review-guide.md** | ~750 | Core Web Vitals/N+1/memory/complexity (on-demand) | @@ -108,6 +110,7 @@ code-review-skill/ │ ├── go.md # Go patterns (on-demand) │ ├── c.md # C patterns (on-demand) │ ├── cpp.md # C++ patterns (on-demand) +│ ├── qt.md # Qt patterns (on-demand) │ ├── css-less-sass.md # CSS/Less/Sass patterns (on-demand) │ ├── architecture-review-guide.md # Architecture design review (on-demand) │ ├── performance-review-guide.md # Performance review (on-demand) @@ -227,6 +230,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file | **Go** | 错误处理、goroutine/channel、context 传播、接口设计、测试模式 | | **C** | 指针/缓冲区安全、UB、资源管理、错误处理 | | **C++** | RAII、生命周期、Rule of 0/3/5、异常安全 | +| **Qt** | 对象模型、信号/槽、内存管理(父子关系)、线程安全、GUI 性能 | | **CSS/Less/Sass** | CSS 变量规范、!important 使用、性能优化、响应式设计、浏览器兼容性 | | **TanStack Query** | v5 最佳实践、queryOptions、useSuspenseQuery、乐观更新 | | **架构设计** | SOLID 原则、架构反模式、耦合度/内聚性、分层架构 | @@ -246,6 +250,7 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file | **reference/go.md** | ~990 | Go goroutine/channel/context/接口(按需加载)| | **reference/c.md** | ~210 | C 内存安全/UB/错误处理(按需加载)| | **reference/cpp.md** | ~300 | C++ RAII/生命周期/移动语义(按需加载)| +| **reference/qt.md** | ~190 | Qt 对象模型/信号槽/GUI 性能(按需加载)| | **reference/css-less-sass.md** | ~660 | CSS/Less/Sass 变量/性能/响应式(按需加载)| | **reference/architecture-review-guide.md** | ~470 | SOLID/反模式/耦合度分析(按需加载)| | **reference/performance-review-guide.md** | ~750 | Core Web Vitals/N+1/内存/复杂度(按需加载)| @@ -301,6 +306,7 @@ code-review-skill/ │ ├── go.md # Go 模式(按需加载) │ ├── c.md # C 模式(按需加载) │ ├── cpp.md # C++ 模式(按需加载) +│ ├── qt.md # Qt 模式(按需加载) │ ├── css-less-sass.md # CSS/Less/Sass 模式(按需加载) │ ├── architecture-review-guide.md # 架构设计审查(按需加载) │ ├── performance-review-guide.md # 性能审查(按需加载) diff --git a/SKILL.md b/SKILL.md index c5b9c6d..bc31627 100644 --- a/SKILL.md +++ b/SKILL.md @@ -185,6 +185,7 @@ Use labels to indicate priority: | **C** | [C Guide](reference/c.md) | 指针/缓冲区, 内存安全, UB, 错误处理 | | **C++** | [C++ Guide](reference/cpp.md) | RAII, 生命周期, Rule of 0/3/5, 异常安全 | | **CSS/Less/Sass** | [CSS Guide](reference/css-less-sass.md) | 变量规范, !important, 性能优化, 响应式, 兼容性 | +| **Qt** | [Qt Guide](reference/qt.md) | 对象模型, 信号/槽, 内存管理, 线程安全, 性能 | ## Additional Resources diff --git a/reference/qt.md b/reference/qt.md new file mode 100644 index 0000000..24fef2b --- /dev/null +++ b/reference/qt.md @@ -0,0 +1,186 @@ +# Qt Code Review Guide + +> Code review guidelines focusing on object model, signals/slots, event loop, and GUI performance. Examples based on Qt 5.15 / Qt 6. + +## Table of Contents + +- [Object Model & Memory Management](#object-model--memory-management) +- [Signals & Slots](#signals--slots) +- [Containers & Strings](#containers--strings) +- [Threads & Concurrency](#threads--concurrency) +- [GUI & Widgets](#gui--widgets) +- [Meta-Object System](#meta-object-system) +- [Review Checklist](#review-checklist) + +--- + +## Object Model & Memory Management + +### Use Parent-Child Ownership Mechanism +Qt's `QObject` hierarchy automatically manages memory. For `QObject`, prefer setting a parent object over manual `delete` or smart pointers. + +```cpp +// ❌ Manual management prone to memory leaks +QWidget* w = new QWidget(); +QLabel* l = new QLabel(); +l->setParent(w); +// ... If w is deleted, l is automatically deleted. But if w leaks, l also leaks. + +// ✅ Specify parent in constructor +QWidget* w = new QWidget(this); // Owned by 'this' +QLabel* l = new QLabel(w); // Owned by 'w' +``` + +### Use Smart Pointers with QObject +If a `QObject` has no parent, use `QScopedPointer` or `std::unique_ptr` with a custom deleter (use `deleteLater` if cross-thread). Avoid `std::shared_ptr` for `QObject` unless necessary, as it confuses the parent-child ownership system. + +```cpp +// ✅ Scoped pointer for local/member QObject without parent +QScopedPointer obj(new MyObject()); + +// ✅ Safe pointer to prevent dangling pointers +QPointer safePtr = obj.data(); +if (safePtr) { + safePtr->doSomething(); +} +``` + +### Use `deleteLater()` +For asynchronous deletion, especially in slots or event handlers, use `deleteLater()` instead of `delete` to ensure pending events in the event loop are processed. + +--- + +## Signals & Slots + +### Prefer Function Pointer Syntax +Use compile-time checked syntax (Qt 5+). + +```cpp +// ❌ String-based (runtime check only, slower) +connect(sender, SIGNAL(valueChanged(int)), receiver, SLOT(updateValue(int))); + +// ✅ Compile-time check +connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue); +``` + +### Connection Types +Be explicit or aware of connection types when crossing threads. +- `Qt::AutoConnection` (Default): Direct if same thread, Queued if different thread. +- `Qt::QueuedConnection`: Always posts event (thread-safe across threads). +- `Qt::DirectConnection`: Immediate call (dangerous if accessing non-thread-safe data across threads). + +### Avoid Loops +Check logic that might cause infinite signal loops (e.g., `valueChanged` -> `setValue` -> `valueChanged`). Block signals or check for equality before setting values. + +```cpp +void MyClass::setValue(int v) { + if (m_value == v) return; // ? Good: Break loop + m_value = v; + emit valueChanged(v); +} +``` + +--- + +## Containers & Strings + +### QString Efficiency +- Use `QStringLiteral("...")` for compile-time string creation to avoid runtime allocation. +- Use `QLatin1String` for comparison with ASCII literals (in Qt 5). +- Prefer `arg()` for formatting (or `QStringBuilder`'s `%` operator). + +```cpp +// ❌ Runtime conversion +if (str == "test") ... + +// ✅ Prefer QLatin1String for comparison with ASCII literals (in Qt 5) +if (str == QLatin1String("test")) ... // Qt 5 +if (str == u"test"_s) ... // Qt 6 +``` + +### Container Selection +- **Qt 6**: `QList` is now the default choice (unified with `QVector`). +- **Qt 5**: Prefer `QVector` over `QList` for contiguous memory and cache performance, unless stable references are needed. +- Be aware of Implicit Sharing (Copy-on-Write). Passing containers by value is cheap *until* modified. Use `const &` for read-only access. + +```cpp +// ❌ Forces deep copy if function modifies 'list' +void process(QVector list) { + list[0] = 1; +} + +// ✅ Read-only reference +void process(const QVector& list) { ... } +``` + +--- + +## Threads & Concurrency + +### Subclassing QThread vs Worker Object +Prefer the "Worker Object" pattern over subclassing `QThread` implementation details. + +```cpp +// ❌ Business logic inside QThread::run() +class MyThread : public QThread { + void run() override { ... } +}; + +// ✅ Worker object moved to thread +QThread* thread = new QThread; +Worker* worker = new Worker; +worker->moveToThread(thread); +connect(thread, &QThread::started, worker, &Worker::process); +thread->start(); +``` + +### GUI Thread Safety +**NEVER** access UI widgets (`QWidget` and subclasses) from a background thread. Use signals/slots to communicate updates to the main thread. + +--- + +## GUI & Widgets + +### Logic Separation +Keep business logic out of UI classes (`MainWindow`, `Dialog`). UI classes should only handle display and user input forwarding. + +### Layouts +Avoid fixed sizes (`setGeometry`, `resize`). Use layouts (`QVBoxLayout`, `QGridLayout`) to handle different DPIs and window resizing gracefully. + +### Blocking Event Loop +Never execute long-running operations on the main thread (freezes GUI). +- **Bad**: `Sleep()`, `while(busy)`, synchronous network calls. +- **Good**: `QProcess`, `QThread`, `QtConcurrent`, or asynchronous APIs (`QNetworkAccessManager`). + +--- + +## Meta-Object System + +### Properties & Enums +Use `Q_PROPERTY` for values exposed to QML or needing introspection. +Use `Q_ENUM` to enable string conversion for enums. + +```cpp +class MyObject : public QObject { + Q_OBJECT + Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged) +public: + enum State { Idle, Running }; + Q_ENUM(State) + // ... +}; +``` + +### qobject_cast +Use `qobject_cast` for QObjects instead of `dynamic_cast`. It is faster and doesn't require RTTI. + +--- + +## Review Checklist + +- [ ] **Memory**: Is parent-child relationship correct? Are dangling pointers avoided (using `QPointer`)? +- [ ] **Signals**: Are connections checked? Do lambdas use safe captures (context object)? +- [ ] **Threads**: Is UI accessed only from main thread? Are long tasks offloaded? +- [ ] **Strings**: Are `QStringLiteral` or `tr()` used appropriately? +- [ ] **Style**: Naming conventions (camelCase for methods, PascalCase for classes). +- [ ] **Resources**: Are resources (images, styles) loaded from `.qrc`? \ No newline at end of file