c – boost :: any_range>在发布模式下崩溃

我正在观察下面这段代码的一个相当奇怪的行为:

#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));
}

这里的想法是隔离一个字符串序列的实际表示形式,这些字符串由any_range和gsl :: string_span后面的函数f作为参数接收(注意,提交将string_view更改为string_span已经在几个小时前发布到GSL).

我的原始代码没有const T作为any_range的参考模板参数(它是一个简单的T)并且在执行期间崩溃了.但是,这只发生在Release模式下,在Debug或RelWithDebInfo(由CMake生成)中运行正常.我使用的是VS2013 / 2015 x64.此外,尝试调试完整的Release版本,将调试输出添加到转换lambda消除了崩溃(我的猜测是它阻止了一些内联).我最后的工作解决方案是将const T指定为Reference.

但是,我仍然想知道为什么崩溃发生在第一位?是VS编译器错误吗?在当前执行string_span的错误?或者我只是滥用boost :: any_range?

编辑

刚刚使用clang 3.7.0构建版本,行为类似(在调试中运行正常,不会崩溃,但输出带有-O2的const T的垃圾).所以它似乎不像编译器问题.

最佳答案 事实证明,any_range的dereference方法将返回对T的引用,除非将Reference类型指定为const T,从而创建对临时的悬空引用.这是因为使用了
any_iterator_interface.hpp中定义的any_incrementable_iterator_interface :: mutable_reference_type_generator.

因此,正确解决问题的方法是在迭代器解除引用返回临时值的情况下将const T指定为Reference类型.

点赞