2015-11-05 89 views
4

我观察下面的代码段的一个相当怪异的行为:的boost :: any_range <GSL :: string_span <>>坠毁在Release模式

#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_rangegsl::string_span(注意,提交更改string_viewstring_span已在几个小时前提交给GSL)后作为参数通过功能f接收的一系列字符串。

我原来的代码没有一个const TReference模板参数any_range(这是一个简单的T),并在执行过程中坠毁。然而,这只发生在发布模式下,在Debug或RelWithDebInfo(由CMake生成)中工作正常。我用VS2013/2015 x64。此外,试图调试完整的发布版本,添加调试输出到转换lambda消除了崩溃(我的猜测是它阻止了一些内联)。我的最终工作解决方案是将const T指定为Reference

但是,我仍然想知道为什么是否首先崩溃?它是VS编译器错误吗?目前执行中的错误string_span?或者我只是在滥用boost::any_range

编辑

刚刚建成的版本铿锵3.7.0和行为是相似的(在调试工作正常,并不会崩溃,但没有const T-O2输出垃圾)。所以它看起来不像编译器问题。

+0

祝你好运调试。你试过调试它吗?您可以在发行模式下进行调试。 –

+0

@WarrenP当然。但它在Debug/RelWithDebInfo模式下工作得很好,甚至在Release模式下的lambda中也有一些调试输出,有点让调试真的很难:) – Rostislav

回答

0

快速查看后,我怀疑问题在于你的lambda。如果我理解正确的话,你最终采取了std::string通过const引用与下面的参数声明:

const typename C::value_type& v

但是,您然后使用v构建cstring_span。这里的揉:cstring_span只有一个构造函数从非const引用到容器类型(如std::string)。从概念上讲,构造看起来是这样的:

template <class Cont> cstring_span(Cont& c)

所以我猜测,当你从你的拉姆达返回,临时被从v创建,然后传递给cstring_span构造,以提供非-const引用参数。当然,一旦临时清理完毕,您的cstring_span就会悬空。

+0

谢谢Neil。然而,在这种情况下,'Cont'被推断为'std :: string const'并且没有临时创建(我只是单步执行代码并查看调用堆栈)。此外,我会假设这样一个悬而未决的引用也会崩溃Debug版本。我会更深入地研究它,并试图找出问题实际是什么。 – Rostislav

2

事实证明,所述any_rangedereference方法将一个引用,除非Reference类型被指定为const T,因此形成了悬空参考到临时返回T。发生这种情况是由于使用了any_iterator_interface.hpp中定义的any_incrementable_iterator_interface::mutable_reference_type_generator

因此,如果迭代器取消引用返回临时值,则问题的正确解决方案确实将const T指定为Reference类型。

相关问题