【问题标题】:How to prevent QStringBuilder from outliving the scope it was initialised in如何防止 QStringBuilder 超出其初始化范围
【发布时间】:2015-12-05 06:00:41
【问题描述】:

我一直在考虑更改一些代码以将QStringBuilder 表达式模板用于其purported performance improvements。不幸的是,这导致我的代码部分开始在某些地方崩溃,下面是一个示例:

#define QT_USE_QSTRINGBUILDER
#include <numeric>
#include <vector>
#include <QString>
#include <QStringBuilder>

int main()
{
    std::vector<int> vals = {0, 1, 2, 3, 4};
    QString text = "Values: " + QString::number(vals[0]);
    text = std::accumulate(vals.begin() + 1, vals.end(), text, [](const QString& s, int i)
    {
        return s + ", " + QString::number(i);
    });
}

这个崩溃的原因是因为 lambda 表达式的返回类型被推断为 QStringBuilder&lt;QStringBuilder&lt;QString,const char [3]&gt;,QString&gt;,在返回后尝试转换为 QString 以分配给 accumulate 结果。这个转换崩溃是因为它试图使用对 lambda 范围内的对象的引用,这些对象现在已被销毁。可以通过显式指定 lambda 的返回类型来修复此崩溃,例如 [](const QString&amp; s, int i) -&gt; QString,这可确保在退出闭包之前发生强制转换。

然而,在此处启用QStringBuilder 会导致以前工作的代码崩溃,甚至没有发出警告,这意味着我现在将避免在其他地方使用它,除非我能保证这种情况不会再次发生。由于在这种情况下,RVO 可以防止发生任何复制,我认为禁用对象复制的常用技术不会起作用。有没有办法防止在QStringBuilder 或类似的表达式模板中发生这种情况,或者维护对自动变量的引用的对象总是不安全使用?

【问题讨论】:

  • 这是一个 Qt 错误。如果还没有提交,请提交,它应该很快就会修复。
  • QStringBuilder 与 C++11 兼容,但目前不与 C++14 兼容……这本质上是一个 C++14,而不是 C++11 问题。
  • @KubaOber 在 C++11 中不需要指定带有单个 return 语句的 lambda 表达式的返回类型,这就是导致此问题的原因。
  • @KubaOber 这个错误has already been filed 并作为“超出范围”关闭。

标签: c++ qt c++11 expression-templates


【解决方案1】:

lambda 应该返回一个显式类型:

[]() -> Type { }

or 

[]() -> QString { }

【讨论】:

  • 我在问题中提到这解决了这个实例的问题,但我并不是要解决这个特定的崩溃,而是 QStringBuilder 类本身,因为返回类型规范对于 lambdas 不是强制性的,而不是即使是 C++14 中的函数。通过这种隐含行为导致崩溃的风险目前是不可接受的。
  • 呃,我应该仔细阅读这个问题,或者可能是稍后添加的。
【解决方案2】:

clazy 代码检查器提供check for this scenario

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-20
    • 2015-01-09
    • 2021-05-14
    • 2020-09-03
    • 1970-01-01
    • 2012-08-13
    相关资源
    最近更新 更多