【发布时间】:2023-03-28 13:45:01
【问题描述】:
背景:
考虑以下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.
使用 clang 编译并启用range-loop-analysis 诊断时:
$ clang++ -Wrange-loop-analysis -o test test.cpp
问题:
根据https://reviews.llvm.org/D4169,警告在以下时间发出:
for (const Foo &x : Foos),其中 Foos 范围仅返回一个副本。建议使用非引用类型,这样文案就很明显了
我完全理解std::vector<bool> 的迭代器返回代理类型的副本(而不是引用),但我不同意“所以副本显而易见”的说法:
- “隐藏”复制操作到底发生在哪里?据我所知,我们只是将引用绑定到一个临时对象,这应该会延长临时对象的生命周期以匹配参考。
- 即使我们已经编写了
for(const auto element : vectorBool)(这样警告就会消失),我们在C++17's guaranteed copy elision rules 下也不应该有复制/移动操作(甚至在使用任何体面的编译器时在C++ 17 之前),所以关于使 省略 复制操作明显的警告吗?!
【问题讨论】:
-
乍一看,对于您发布的代码,这个警告对我来说看起来很愚蠢/错误。
-
@JesperJuhl 不幸的是,代理类型收到了这个警告,但我怀疑分析器能否区分代理和一些奇怪的东西。如果一切都失败了,责备
std::vector<bool> -
@Passer By -
vector<bool>,是的,我希望它从未被创建过.. -
@Mike 我也不希望看到这种情况发生。分析只看类型,推断返回值不可能是容器中的元素,something一定是被复制了。然后它建议写
auto : Foos以明确这一事实。在这种情况下,代理在概念上没有复制任何东西,但我怀疑分析器可以对此做任何事情。它试图警告人们注意奇怪的非代理案例。 -
@Mike 考虑某种范围适配器,例如
uppercase(some_vector_of_strings)。它不可能返回对容器中对象的引用,因为它必须在返回之前修改每个元素。
标签: c++ clang compiler-warnings clang++ copy-elision