【问题标题】:Pass object (that will go out of scope) by reference通过引用传递对象(将超出范围)
【发布时间】:2015-12-28 04:49:58
【问题描述】:

所以我有这个功能:

addDataToList(..., QVariant metadata) { }

本例中相关的QVariant构造函数为:QVariant(const QString & val)

现在我有一个函数foo(),我从那里调用addDataToList() 函数。 如何将有效值传递给QVariant 对象?

如果我有这样的事情:

void foo() {
    QString str = "String";
    addDataToList(..., QVariant(str));
}

它不起作用,因为str 对象将超出范围,导致未定义的行为。

但如果我在堆上创建字符串,如下所示:

void foo() {
    QString *str = new QString("String");
    addDataToList(..., QVariant(*str));
}

它会起作用,但会出现一些内存泄漏(因为QVariant 不获取传递的指针的所有权)。

我该如何解决这种情况?

编辑:这是addDataToList(...)的实际实现:

void TPMSvalidator::addDataToList(const QString &data, bool useMetadata, MessageTypes type, QVariant metadata) {
    QString text;
    QIcon okIcon(QDir::currentPath() + "\\Resources\\Icons\\ok3.png");
    QIcon notOkIcon(QDir::currentPath() + "\\Resources\\Icons\\notok.png");
    QIcon noticeIcon(QDir::currentPath() + "\\Resources\\Icons\\warning2.png");

    if (data != QString()) {
        QListWidgetItem *data_w = new QListWidgetItem;

        if (type == MessageTypes::notification) {
            data_w->setBackgroundColor(QColor(Qt::GlobalColor::gray));
            data_w->setTextColor(QColor(Qt::GlobalColor::black));
            data_w->setIcon(noticeIcon);
            text.append("NOTICE: ");
        }
        else if (type == MessageTypes::telegramOkInfo) {
            data_w->setBackgroundColor(QColor(Qt::GlobalColor::gray));
            data_w->setTextColor(QColor(Qt::GlobalColor::black));
            data_w->setIcon(okIcon);
            text.append("INFO: ");
        }
        else if (type == MessageTypes::telegramNotOkInfo) {
            data_w->setBackgroundColor(QColor(Qt::GlobalColor::gray));
            data_w->setTextColor(QColor(Qt::GlobalColor::red));
            data_w->setIcon(notOkIcon);
            text.append("INFO: ");
        }
        else if (type == MessageTypes::warning) {
            data_w->setBackgroundColor(QColor(Qt::GlobalColor::darkYellow));
            data_w->setTextColor(QColor(Qt::GlobalColor::black));
            text.append("WARNING: ");
        }
        else {
            data_w->setBackgroundColor(QColor(Qt::GlobalColor::darkRed).light(130));
            data_w->setTextColor(QColor(Qt::GlobalColor::white));
            data_w->setIcon(notOkIcon);
            text.append("ERROR: ");
        }

        text.append(data);
        data_w->setText(text);
        data_w->setFont(QFont("Helvetica"));

        if (useMetadata) {
            data_w->setData(Qt::UserRole, metadata);
        }

        ui.listData->addItem(data_w);

        if (ui.autoScrollCheckBox->isChecked()) {
            ui.listData->scrollToBottom();
        }
    }
}

【问题讨论】:

  • 如果你这样做,你需要自己处理内存清理。您可以免费使用。
  • QT 示例表明 QVariant 实际上复制了传递的值。你确定不是吗? (即QVariant x, y(QString()), z(QString("")); 在示例中)。在这种情况下它不应该使用 const-ref,但是 QT 并没有那么快地更新到最新的 C++。
  • const & 参数一般为 1. 承诺不更改值 2. 避免为函数调用制作副本。它不一定表示将保留引用。
  • QVariant 仅存储副本。 (否则它几乎没用。)
  • 您对第一个场景的解释是错误的......按值传递将临时复制到函数调用堆栈中,即 addDataToList() 将拥有它自己的副本。所以,它不会超出范围跨度>

标签: c++ memory-leaks reference pass-by-reference undefined-behavior


【解决方案1】:

堆栈上带有临时对象的第一个版本将安全地工作,因为临时 QString 按值复制到 QVariant 中 - 不仅仅是引用。

【讨论】:

    【解决方案2】:

    addDataToList(..., QVariant metadata) { }
    

    您正在接受QVariant 的价值。因此,您将复制传递给函数的值。所以在

    addDataToList(..., QVariant(str));
    

    您创建一个临时的QVariant,并将该临时的内容复制到metadata 中的addDataToList()。现在metadata 是它自己的对象,不依赖于您创建的临时对象。

    【讨论】:

    • 那为什么我随机得到First-chance exception at 0x013D0497 (Qt5Guid.dll) in app.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x00272FF4)? (并且调试器指向addDataToList() 方法的末尾大括号)。如果我使用指针并动态分配内存,问题就消失了! (当然,只有一些内存泄漏,但没有随机崩溃)。
    • @MariusMarusanici 你在addDataToList()做什么?如果您遇到异常,为什么不发布呢?
    • @MariusMarusanici:堆栈溢出通常是由无限递归引起的。这是与悬空指针不同的问题。
    猜你喜欢
    • 2012-04-14
    • 1970-01-01
    • 2019-05-31
    • 2016-05-29
    • 2017-09-11
    • 2011-07-06
    • 2012-07-07
    • 2012-01-05
    相关资源
    最近更新 更多