使用clang优化编译时得到意外结果
Getting unexpected result when compiling with clang optimization
我在我的代码中发现了一个bug,只有当我启用编译器优化- 01或更高时才会发生。我跟踪了这个bug,似乎我不能在优化启用时在boost转换范围上使用boost type_erase适配器。我写了这个c++程序来复制它:
#include <iostream>
#include <vector>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/adaptor/type_erased.hpp>
using namespace boost::adaptors;
using namespace std;
int addOne(int b) {
return b + 1;
}
int main(int, char**) {
vector<int> nums{ 1, 2, 3 };
auto result1 = nums | transformed(addOne) | type_erased<int, boost::forward_traversal_tag>();
auto result2 = nums | transformed(addOne);
auto result3 = nums | type_erased<int, boost::forward_traversal_tag>();
for (auto n : result1)
cout << n << " ";
cout << endl;
for (auto n : result2)
cout << n << " ";
cout << endl;
for (auto n : result3)
cout << n << " ";
cout << endl;
}
当我在没有任何优化的情况下运行这个程序时,我得到以下输出:
2 3 4
2 3 4
1 2 3
当我使用- 01标志运行它时,我得到以下结果:
1 1 1
2 3 4
1 2 3
我正在使用clang++来编译它。我使用的clang版本是:
Apple LLVM version 8.0.0 (clang-800.0.38)
我不知道是我做错了什么,还是它是一个boost/clang错误。
编辑:改成
type_erased<int, boost::forward_traversal_tag, const int>()
,它现在工作。第三个模板参数是引用类型,将引用设置为const会延长转换后创建的临时对象的时间范围。
EDIT事实上,这比你看到的要复杂得多。还有另一个可用性问题,它确实解决了这个问题。参见OP的自我回答
你正陷入Boost Range v2(和Boost Proto等)的1号陷阱。
nums | transformed(addOne)
是临时的。type_erased
适配器存储一个引用到它。
将类型擦除适配器赋值给resultN
变量后,临时适配器将被销毁。
你得到的是一个悬空引用:(
这是一个非常不直观的效果,也是我在代码库中限制使用Range V2的第一个原因:我已经太经常使用Range V2了。
这是一个解决方法:
auto tmp = nums | transformed(addOne);
auto result = tmp | type_erased<int, boost::forward_traversal_tag>();
-fsanitize=address,undefined
在使用命名的临时时确认UB已经消失。
使用
type_erased<int, boost::forward_traversal_tag, const int>()
。第三个模板参数是引用类型,将引用设置为const会延长转换后创建的临时对象的时间范围。
相关文章:
- 尝试将字符串/字符转换为整数会产生意外结果
- RapidXML - 代码创建意外结果
- 类中静态函数C++意外结果
- 指针数组中的意外结果
- 使用指针访问数组元素时出现意外结果
- 使用 sprintf 和 %g 将双精度转换为字符串的意外结果
- C++:比较运算符>和字符串文本的意外结果
- 具有意外结果的 C++ 闭包
- yaml-cpp 比较的意外结果
- 每次都出现意外结果
- 在 Qt 中解析嵌套的 JSON 时出现意外结果(数组不存在)
- 如何避免 std::abs 的意外结果?
- 使用嵌套 if 语句的意外结果
- A ^= B ^= A ^= B;C# Visual Studio 中的意外结果
- 逻辑错误,我将获得意外结果
- 在 c++ 中使用异步的意外结果
- 从函数的返回值将元素C++存储到 std::vector 中时出现意外结果
- 执行递增和递减时"cout"链接会产生意外结果
- OpenCL - 内核方法返回意外结果
- C++使用 std::get_time 解析 YYMMDD ISO 8601 日期字符串会得到意外结果