代码之家  ›  专栏  ›  技术社区  ›  Edward Falk

clang tidy:`循环变量已复制,但仅用作常量引用;考虑让它成为一个永久的参照物——它真的重要吗?

  •  3
  • Edward Falk  · 技术社区  · 4 年前

    我正在编写代码,叮叮当当的tidy到处都在用它标记

    Loop variable is copied but only used as const reference; consider making it a const reference
    

    当前代码:

    for (auto foo : collection) {
        ...
    }
    

    clang tidy建议我使用:

    for (const auto &foo : collection) {
        ...
    }
    

    我当然可以看到const引用比实际复制值更有效,但我想知道编译器是否会这样优化它?我不想白费力气去钻研和改变成百上千个循环。

    1 回复  |  直到 4 年前
        1
  •  7
  •   user17732522    4 年前

    构造函数除了构造新对象之外,还有其他副作用。因此,这两个版本的语义可能有所不同。

    即使情况并非如此,编译器也可能无法在编译期间确定这一点。例如,如果 foo 类型未在同一翻译单元中定义,并且未使用链接时间优化,编译器将无法优化掉副本,因为它可能具有在当前翻译单元编译时未知的副作用。

    类似地,循环体可能会调用编译器无法证明它们没有修改的函数 ,在这种情况下,也无法优化副本。

    (顺便说一句,编译器要证明这一点比clang tidy给你警告要困难得多,因为即使是一个函数 const 技术上仍然允许修改它。即使 对象本身是 常数 -合格的(例如。 const auto ),功能可能取决于 对象通过其他程序路径访问。)

    例子:

    auto f(const std::vector<std::string>& x) {
        std::size_t n = 0;
        for(auto y : x)
            n += y.size();
        return n;
    }
    

    GCC和叮当声 -O3 libstdc++不会优化拷贝(请参阅 operator new / operator delete / memcpy 程序集中的调用): https://godbolt.org/z/d66ac617M

    https://godbolt.org/z/Tdc3GhcEv


    如果你知道 是简单的,例如,类似于 std::vector<int> 容器,那么就性能而言,它实际上并不重要,假设可观察到的行为是相同的。

    您可能仍然希望使用 常数 常数 第三部分,用于在整个代码中保持常量的正确性。然而,这是多么必要,可能会进入基于意见的领域。