【问题标题】:Don't call QString::operator[]() on temporary不要临时调用 QString::operator[]()
【发布时间】:2018-02-20 01:01:53
【问题描述】:

我在我的代码上运行 clazy 并收到有关此类代码的警告:

QChar value() const
{
    if (hide_content_)
        return '\0';
    else
        return text()[0];
}

其中text() 有这样的签名QString text() const;

警告是:

warning: Don't call QString::operator[]() on temporary
      [-Wclazy-detaching-temporary]
            return text()[0];
                   ^

但这意味着什么?临时QString 对象是否有可能被销毁 在致电operator[]之前?

【问题讨论】:

  • @eyllanesc 谢谢,我只是在docs 中寻找文档,但永远不要考虑在src/ 中挖掘
  • 帮助他人。发布minimal reproducible example
  • @user1244932,事实上,深入src/ 不会给你任何检查背后的理由,你只会发现那里是如何实施检查的:)
  • @Mike 嗯,你错了。出于某种原因,他们在src/ 下持有降价文档。

标签: c++ qt


【解决方案1】:

在调用 operator[] 之前,临时 QString 对象是否可能被销毁?

不,警告不是关于不安全的操作。此处的行为完全定义为临时的 aren't destroyed 直到创建它们的完整表达式结束(即在您的情况下直到 return 语句结束)。

总结:警告是关于与操作相关的性能问题。您可以使用.at(0) 而不是.operator[](0) 来修复它。如需解释,请继续阅读答案。


首先,Qt的容器是implicitly shared;这意味着当你复制一个容器时,它的元素实际上不会被复制,直到对容器执行写操作(又名写时复制)。

这意味着容器在检测到写入操作时需要分离(执行深拷贝),以便这种隐式共享对用户保持透明。

这包括容器分发对其内部项目的非常量引用的情况(正是非常量 operator[] 正在做什么),因为它无法提前知道您(容器用户)实际上将如何使用这些非常量引用。

换句话说,假设我们有一个QString str = "abc";,当您编写QChar ch = str[0];QString 的非常量operator[] 被调用,对于容器来说,这正是它知道什么时候用户写str[0] = 'x';。这意味着每当调用非常量操作时,容器都需要分离。当他/她真的不打算更改容器中的任何内容时,使用 const 函数是用户的工作。

这里的 Clazy 试图检测用户在临时对象中获得非常量引用的情况(因为对即将被销毁的临时对象进行变异实际上没有意义)。


更多信息:

  1. Uncovering 32 Qt best practices at compile time with clazy - 见#8
  2. Effective Qt - Marc Mutz - Meeting C++ 2015

【讨论】:

  • 你能解释一下为什么非 const operator[] 会被调用而不是 const operator[] 吗?
  • @SteakOverflow, const operator[] 仅在使用对对象的 const 引用时调用,因此作为答案中提供的修复的替代方法,可以使用 C++-17 的 std::as_const 或 Qt 的qAsConst 获取对对象的 const 引用。
  • @SteakOverflow,但如果不对问题中的代码进行一些修改,这将无法工作,因为右值删除了 std::as_constqAsConst
猜你喜欢
  • 1970-01-01
  • 2017-05-27
  • 1970-01-01
  • 2015-10-19
  • 1970-01-01
  • 1970-01-01
  • 2018-07-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多