// ============================================================================
//  qt_pitfall_double_connect —— 坑点最小复现：重复 connect 导致槽触发多次
//  对应教案：OUTLINE_4DAY.md Day2 下午 ★坑卡「重复 connect 导致槽触发多次」
//  配套文档：docs/teaching/examples/pitfall_double_connect/README.md
//
//  现象还原：「点一次按钮弹两次框」——根源不在按钮，在 connect 被执行了两次。
//  同时演示 Qt::UniqueConnection 防重（只对成员函数指针有效，lambda 用不了）。
//  确定性输出，无 UB，离屏/终端直接跑，退出码 0。
// ============================================================================

#include <QCoreApplication>
#include <QDebug>
#include <QObject>

class Button : public QObject {
    Q_OBJECT
public:
    using QObject::QObject;
signals:
    void clicked();
};

class Popup : public QObject {
    Q_OBJECT
public:
    using QObject::QObject;
    int shownCount = 0;
public slots:
    void showOnce() {
        ++shownCount;
        qInfo() << "  弹框！（第" << shownCount << "次）";
    }
};

int main(int argc, char* argv[]) {
    QCoreApplication app(argc, argv);
    Button btn;
    Popup popup;

    // 典型事故现场：connect 写在会被反复执行的函数里（比如每次打开某个界面
    // 都调一次 setup()），每调一次就多一条连接——信号一发，槽被调 N 次。
    auto setup = [&]() { QObject::connect(&btn, &Button::clicked, &popup, &Popup::showOnce); };
    setup();
    setup();   // 第二次“初始化”——现实里往往藏在另一条调用路径上

    qInfo() << "重复 connect 两次后，点一次按钮：";
    emit btn.clicked();
    qInfo() << "槽被调用了" << popup.shownCount << "次（预期演示值：2）";

    // 修复一：连接前先断开旧连接
    QObject::disconnect(&btn, &Button::clicked, &popup, &Popup::showOnce);
    QObject::disconnect(&btn, &Button::clicked, &popup, &Popup::showOnce);

    // 修复二：Qt::UniqueConnection——同一对(发送者,信号,接收者,槽)只允许一条连接。
    // 注意它只认成员函数指针；lambda 没有身份，UniqueConnection 对 lambda 无效。
    popup.shownCount = 0;
    QObject::connect(&btn, &Button::clicked, &popup, &Popup::showOnce, Qt::UniqueConnection);
    QObject::connect(&btn, &Button::clicked, &popup, &Popup::showOnce, Qt::UniqueConnection);

    qInfo() << "改用 Qt::UniqueConnection 连两次后，点一次按钮：";
    emit btn.clicked();
    qInfo() << "槽被调用了" << popup.shownCount << "次（预期演示值：1）";

    qInfo() << "结论：connect 不要写在会被多次执行的路径上；防御手段是"
               "UniqueConnection（仅限成员函数槽）或把 connect 收拢到构造函数里只做一次。";
    return 0;
}

#include "qt_pitfall_double_connect.moc"
