模板泛化类如何卸载释放内存

CustomWidget::~CustomWidget() {
    for (size_t i = 0; i < buttonManager.registerItem.size(); ++i) {
        delete buttonManager.registerItem(exitButton);
    }
}
以上该怎么写删除对象操作,类如下:

template <typename T>
class GenericManager {
public:
    using ConditionFunc = std::function<bool(const T&, const QPoint&)>;
    using ActionFunc = std::function<void(QPainter&, const T&, bool)>;
    GenericManager() {}
    void registerItem(T* item) {
          int count = items.count();
        qWarning("Inserting at index %d, current count: %d", count, count);
        items.insert(count, item);
    }

    void processItems(QPainter& bufferPainter, QMouseEvent* event, QWidget* widget, 
                      ConditionFunc conditionFunc, ActionFunc actionFunc) {
        QPoint cursorPos = event ? event->pos() : widget->mapFromGlobal(QCursor::pos());

        // 将 i 的类型改为 size_t
        for (size_t i = 0; i < items.count(); ++i) {
            T* item = items.at(i);
            if (item) {
                 qWarning("Inserting at index");
                bool shouldHighlight = conditionFunc(*item, cursorPos);
                actionFunc(bufferPainter, *item, shouldHighlight);
            }
        }
    }

private:
    QPtrVector<T> items;
};

使用模板来泛化类,如何增加删除对象的处理,增加代码如下:

 // 提供一个公共方法来获取 items 的数量
    size_t getItemCount() const {
        return items.count();
    }

    // 提供一个公共方法来获取指定索引的元素
    T* getItemAt(size_t index) const {
        if (index < items.count()) {
            return items.at(index);
        }
        return nullptr;
    }

析构函数删除对象:

CustomWidget::~CustomWidget() {
    // 遍历 GenericManager 中的 items 并释放内存
    for (size_t i = 0; i < buttonManager.getItemCount(); ++i) {
        ButtonInfo* item = buttonManager.getItemAt(i);
        if (item) {
            delete item;
        }
    }
}

注意不能用T* item= buttonManager.getItemAt(i);这样, CustomWidget 的析构函数中正确释放内存

T 是未定义的标识符,因为 T 是 GenericManager 类模板的模板参数,在 CustomWidget 类的作用域内并没有这个类型定义。而在 CustomWidget 里使用的是 GenericManager<ButtonInfo>,所以应该明确使用 ButtonInfo* 来接收 getItemAt 方法返回的指针。

调用方式:

void CustomWidget::paintEvent(QPaintEvent *event) {
    bufferPixmap = QPixmap(size());
    //bufferPixmap.fill(Qt::transparent);
    QPainter bufferPainter(&bufferPixmap);

   // drawBackgroundAndBorder(bufferPainter);
    buttonManager.processItems(bufferPainter, nullptr, this, 
        [](const ButtonInfo& button, const QPoint& cursorPos) {
            return button.rect.contains(cursorPos);
        },
        [this](QPainter& painter, const ButtonInfo& button, bool isHighlighted) { // 添加 this 到捕获列表
            QRect drawRect(button.rect.x(), button.rect.y(), button.rect.width(), button.rect.height());
            qWarning("Draw rect: (%d, %d, %d, %d)", drawRect.x(), drawRect.y(), drawRect.width(), drawRect.height());
            QImage img;
            img.loadFromData(isHighlighted ? button.highlight_png : button.normal_png,
                             isHighlighted ? button.highlight_png_size : button.normal_png_size,
                             "PNG");
            if (img.isNull()) {
                    // 使用 qWarning 替代 qDebug
                    qWarning("Failed to load image");
                }
            // 如果 Qt 版本支持,可以保留下面这行
            // painter.setRenderHint(QPainter::Antialiasing); 
            this->simulateLinearGradient(painter, drawRect, QColor(15, 10, 60), QColor(7, 69, 111));
            painter.drawImage(drawRect, img);
        }
    );

    QPainter painter(this);
    painter.drawPixmap(0, 0, bufferPixmap);
}

注意,可以随意设置条件和绘制内容,conditionFun本例是lambda表达式 return button.rect.contains(cursorPos);

绘制结果简单一句img.loadFromData(isHighlighted ? button.highlight_png : button.normal_png,
                             isHighlighted ? button.highlight_png_size : button.normal_png_size,
                             "PNG");

这样充分利用C++的新特性,代码变得简单清晰

在 C++ 的 Lambda 表达式中,方括号 [] 部分被称为捕获列表,它用于指定 Lambda 表达式可以访问哪些外部变量。捕获列表不同的写法有不同的作用,下面详细解释为什么在你的代码里一个 Lambda 用 [],另一个用 [this]

1. [] 捕获列表

[](const ButtonInfo& button, const QPoint& cursorPos) {
    return button.rect.contains(cursorPos);
}

这里使用 [] 表示该 Lambda 表达式不捕获任何外部变量。这个 Lambda 表达式作为 conditionFunc 传递给 buttonManager.processItems 方法,它只依赖于传入的参数 button 和 cursorPos,不需要访问外部作用域中的任何变量,所以捕获列表为空。它的功能仅仅是判断鼠标位置 cursorPos 是否在按钮的矩形区域 button.rect 内。

2. [this] 捕获列表

[this](QPainter& painter, const ButtonInfo& button, bool isHighlighted) {
    QRect drawRect(button.rect.x(), button.rect.y(), button.rect.width(), button.rect.height());
    qWarning("Draw rect: (%d, %d, %d, %d)", drawRect.x(), drawRect.y(), drawRect.width(), drawRect.height());
    QImage img;
    img.loadFromData(isHighlighted ? button.highlight_png : button.normal_png,
                     isHighlighted ? button.highlight_png_size : button.normal_png_size,
                     "PNG");
    if (img.isNull()) {
        qWarning("Failed to load image");
    }
    this->simulateLinearGradient(painter, drawRect, QColor(15, 10, 60), QColor(7, 69, 111));
    painter.drawImage(drawRect, img);
}

这里使用 [this] 表示该 Lambda 表达式捕获当前对象的指针 this。在这个 Lambda 表达式中,调用了 this->simulateLinearGradient 方法,这是当前对象 CustomWidget 的一个成员函数。为了能够访问当前对象的成员函数和成员变量,需要通过 this 指针,所以在捕获列表中指定 this。这样,Lambda 表达式就可以在其内部调用当前对象的方法和访问成员变量了。

总结

  • []:不捕获任何外部变量,Lambda 表达式只能使用其参数列表中的变量。
  • [this]:捕获当前对象的指针,Lambda 表达式可以访问当前对象的成员函数和成员变量。

通过合理使用捕获列表,可以让 Lambda 表达式根据需要访问外部作用域中的变量,从而实现更灵活的功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值