2015-11-05 92 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類型。

相關問題