clang的“范围回路分析”诊断是什么? [英] What is clang's 'range-loop-analysis' diagnostic about?
问题描述
请考虑以下示例:
#include <iostream>
#include <vector>
int main() {
std::vector<bool> vectorBool{false, true};
for(const auto &element : vectorBool) std::cout << std::boolalpha << element << ' ';
return 0;
}
它发出警告:
test.cpp:6:21: warning: loop variable 'element' is always a copy because the range of type 'std::vector<bool>' does not return a reference [-Wrange-loop-analysis]
for(const auto &element : vectorBool) std::cout << std::boolalpha << element << ' ';
^
test.cpp:6:9: note: use non-reference type 'std::_Bit_reference'
for(const auto &element : vectorBool) std::cout << std::boolalpha << element << ' ';
^~~~~~~~~~~~~~~~~~~~~
1 warning generated.
在使用clang和 range-loop-analysis
诊断程序进行编译时已启用:
When compiled using clang with the range-loop-analysis
diagnostic enabled:
$ clang++ -Wrange-loop-analysis -o test test.cpp
问题:
根据 https://reviews.llvm.org/D4169 ,则在以下情况下发出警告:
Questions:
According to https://reviews.llvm.org/D4169, the warning emits when:
for(const Foo& x:Foos),其中范围Foos仅返回副本。建议使用非引用类型,这样副本就很明显
for (const Foo &x : Foos), where the range Foos only return a copy. Suggest using the non-reference type so the copy is obvious
我完全理解 std :: vector< bool>
的迭代器返回代理类型的副本(而不是引用),但是我不同意因此副本很明显的声明:
I completely understand that std::vector<bool>
's iterators return a copy of a proxy type (instead of a reference), but I disagree with the statement "so the copy is obvious":
- 隐藏的确切位置是复制操作正在进行吗?据我所知,我们只是将一个引用绑定到一个临时对象,这将延长该临时对象的寿命以使其与该引用相匹配。
- 即使我们已经为<($ auto $ const auto element)编写了$(code)(以便警告消失),在 C ++ 17的保证复制删除规则(甚至在使用任何体面的编译器的C ++ 17之前),因此此警告是关于使消除复制操作变得明显吗?!
- Where exactly is that "hidden" copy operation taking place? As far as I can see, we are just binding a reference to a temporary object, and this should prolong the lifetime of the temporary to match that of the reference.
- Even in case we have written
for(const auto element : vectorBool)
(so that the warning disappears), We should have no copy/move operations under C++17's guaranteed copy elision rules (and even in pre-C++17 when using any decent compiler), so is this warning about making an elided copy operation obvious?!
推荐答案
在C ++ 17中,基于循环的范围定义为
In C++17 a range based for loop is defined as
{
auto && __range = range_expression ;
auto __begin = begin_expr ;
auto __end = end_expr ;
for ( ; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
并且
range_declaration = *__begin;
是初始化范围变量的地方。通常 * __ begin
返回一个引用,因此在
Is the point where the range variable is initialized. Typically *__begin
returns a reference so in
for (const auto& e : range_that_returns_references)
e
我们就可以使用范围中的元素在
e
can be eliminated and we can just work with the element from the range. In
for (const auto& e : range_that_returns_proxies_or_copies)
e
无法删除。 * __开始
将创建一个代理或副本,然后将该临时目录绑定到 e
。这意味着在每次迭代中,都有一个要创建和销毁的对象,这可能会很昂贵,并且在使用引用时并不明显。该警告希望您使用非引用类型来表明您实际上不是在使用该范围中的元素,而是使用该元素的副本/代理。
e
can't be eleminated. *__begin
will create a proxy or copy and then we bind that temporary to e
. That means in every iteration you have an object that is being crated and destroyed ,which could be costly, and is not obvious as you are using a reference. The warning wants you to use a non reference type to make it obvious that you are not actually working with the element from the range but instead a copy/proxy of it.
这篇关于clang的“范围回路分析”诊断是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!