我观察到以下代码的一个相当奇怪的行为:
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/any_range.hpp>
#include <vector>
#include <string>
#include <iostream>
#include "gsl.h"
template <typename T>
using ImmutableValueRange = boost::any_range<T, boost::bidirectional_traversal_tag, /*const*/ T>;
template <typename T, typename C>
ImmutableValueRange<T> make_transforming_immutable_range(const C& container)
{
return container | boost::adaptors::transformed([](const typename C::value_type& v) -> T
{
//std::cout << "trans : " << T{ v }.data() << "\n";
return T{ v };
});
}
void f(ImmutableValueRange<gsl::cstring_span<>> r)
{
for (const auto& c : r) {
std::cout << c.data() << "\n";
}
}
int main()
{
std::vector<std::string> v({ "x", "y", "z" });
f(make_transforming_immutable_range<gsl::cstring_span<>>(v));
}
这里的想法是隔离函数作为参数接收的字符串序列的实际表示f
后面一个any_range
and gsl::string_span
(注意,提交改变string_view
to string_span
几个小时前已发送至 GSL)。
我原来的代码没有const T
as Reference
模板参数为any_range
(这是一个简单的T
)并且在执行过程中崩溃了。然而,这种情况只发生在发布模式下,在调试或RelWithDebInfo(由CMake生成)中工作正常。我用的是VS2013/2015 x64。此外,尝试调试完整的发布版本,将调试输出添加到转换 lambda 中消除了崩溃(我的猜测是它阻止了一些内联)。我的最终工作解决方案是指定const T
as Reference
.
然而我还是想知道why事故一开始就发生了吗?是VS编译器的bug吗?当前实施中的错误string_span
?或者我只是滥用了boost::any_range
?
Edit
刚刚使用 clang 3.7.0 构建了版本,行为类似(在调试中工作正常并且不会崩溃,但输出垃圾而没有const T
with -O2
)。所以这看起来不像是编译器问题。
事实证明,any_range
's dereference
方法将返回一个引用T
除非Reference
类型指定为const T
,从而创建对临时对象的悬空引用。发生这种情况是由于使用any_incrementable_iterator_interface::mutable_reference_type_generator
定义于任何_迭代器_接口.hpp http://www.boost.org/doc/libs/1_59_0/boost/range/detail/any_iterator_interface.hpp.
因此,解决问题的正确方法确实是指定const T
as the Reference
类型,以防迭代器解引用返回临时值。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)