考虑以下example:
#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.
使用启用了range-loop-analysis
诊断的clang进行编译时:
$ clang++ -Wrange-loop-analysis -o test test.cpp
根据https://reviews.llvm.org/D4169,警告在以下时间发出:
表示(const Foo&amp; x:Foos),其中范围Foos仅返回副本。建议使用非引用类型,因此副本很明显
我完全理解std::vector<bool>
的迭代器返回代理类型的副本(而不是引用),但我不同意语句&#34;因此副本很明显&#34; :
for(const auto element : vectorBool)
(以便警告消失),我们也应该在C++17's guaranteed copy elision rules下没有复制/移动操作(甚至在使用任何像样的前C ++ 17中也是如此)编译器),所以是关于使省略复制操作变得明显的警告吗? 答案 0 :(得分:8)
在C ++ 17中,基于for循环的范围定义为
{
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
会在
for (const auto& e : range_that_returns_references)
e
可以被删除,我们可以使用范围中的元素。在
for (const auto& e : range_that_returns_proxies_or_copies)
e
无法获得批准。 *__begin
将创建代理或副本,然后我们将该临时绑定到e
。这意味着在每次迭代中,您都有一个被包装和销毁的对象,这可能代价高昂,而且当您使用引用时并不明显。警告要求您使用非引用类型,以明确表示您实际上没有使用范围中的元素,而是使用它的副本/代理。