C++ boost::任何_范围<;gsl::字符串_span<&燃气轮机&燃气轮机;在释放模式下崩溃

C++ boost::任何_范围<;gsl::字符串_span<&燃气轮机&燃气轮机;在释放模式下崩溃,c++,c++11,boost,cpp-core-guidelines,string-span,C++,C++11,Boost,Cpp Core Guidelines,String Span,我观察到以下代码的一个相当奇怪的行为: #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 Immuta

我观察到以下代码的一个相当奇怪的行为:

#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));
}
#包括
#包括
#包括
#包括
#包括
#包括“gsl.h”
模板
使用ImmutableValueRange=boost::any_范围;
模板
ImmutableValueRange生成\u转换\u不可变\u范围(常量C和容器)
{
返回容器| boost::adapters::transformed([](const typename C::value_type&v)->T
{

//std::cout快速查看后,我怀疑问题出在lambda中。如果我理解正确,您最终使用带有以下参数声明的
std::string
常量引用:

const typename C::value\u type&v

但是,您随后使用
v
来构造
cstring\u span
。这里有一个难点:
cstring\u span
只有一个从非常量引用到容器类型的构造函数(如
std::string
)。从概念上讲,该构造函数如下所示:

模板
cstring_span(续与c)


所以我猜,当你从lambda返回时,一个临时变量将从
v
创建,然后传递给
cstring\u span
构造函数,以提供一个非常量引用参数。当然,一旦这个临时变量被清除,你的
cstring\u span
将处于悬空状态。

事实证明,
any_range
dereference
方法将返回对
T
的引用,除非
reference
类型被指定为
const T
,从而创建对临时对象的悬空引用。这是由于使用了中定义的
任何可增量迭代器接口::可变引用类型生成器而发生的。


因此,问题的正确解决方案确实是指定
const T
作为
引用
类型,以防迭代器解引用返回临时值。

这是
boost::range
中的一个错误,一个修复仅在2020年2月合并,但没有将其编入
1.73
。该修复从开始可用e> 1.74


调试很顺利。你试过调试吗?你可以在发布模式下调试。@当然可以。但它在调试/relWithDeInfo模式下工作得非常好,甚至在发布模式下的lambda中有一些调试输出,这让调试变得非常困难:)谢谢你,尼尔。但是,在这种情况下,
Cont
被推断为
std::string const
,并且没有创建临时值(我只是单步浏览代码并查看调用堆栈)。此外,我假设这样一个悬空引用也会使调试版本崩溃。我将深入研究它,并试图找出问题的实质。这最终在1.74中得到了解决