簡體   English   中英

boost::any_range <gsl::string_span<> &gt; 在發布模式下崩潰

[英]boost::any_range<gsl::string_span<>> crash in Release mode

我正在觀察以下代碼段的一個相當奇怪的行為:

#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_rangegsl::string_span (注意,將string_view更改為string_span的提交已在幾個小時前進行GSL)。

我的原始代碼沒有const T作為any_range Reference模板參數(它是一個簡單的T )並且它在執行過程中崩潰了。 但是,這只發生在 Release 模式下,在 Debug 或 RelWithDebInfo(由 CMake 生成)中運行良好。 我使用的是 VS2013/2015 x64。 此外,嘗試調試完整的 Release 版本,將調試輸出添加到轉換 lambda 消除了崩潰(我的猜測是它阻止了一些內聯)。 我的最終工作解決方案是將const T指定為Reference

但是,我仍然想知道為什么首先會發生崩潰? 這是VS編譯器的錯誤嗎? string_span當前實現中的string_span 或者我只是濫用boost::any_range

編輯

剛剛用 clang 3.7.0 構建了版本,行為類似(在調試中工作正常並且不會崩潰,但輸出沒有帶有-O2 const T垃圾)。 所以這似乎不是編譯器問題。

事實證明, any_rangedereference方法將返回對T的引用,除非將Reference類型指定為const T ,從而創建對臨時對象的懸空引用。 發生這種情況是由於使用了any_incrementable_iterator_interface::mutable_reference_type_generator定義的any_incrementable_iterator_interface::mutable_reference_type_generator mutable_reference_type_generator

因此,問題的正確解決方案確實是將const T指定為Reference類型,以防迭代器解引用返回臨時值。

這是boost::range一個錯誤,一個修復程序僅在 2020 年 2 月合並,但沒有進入1.73 該修復自1.74可用

https://github.com/boostorg/range/pull/94

快速瀏覽后,我懷疑問題出在您的 lambda 上。 如果我理解正確,您最終會通過帶有以下參數聲明的 const 引用獲取std::string

const typename C::value_type& v

但是,您隨后使用v來構造cstring_span 這里有問題: cstring_span只有一個構造函數,它從非常量引用到容器類型(如std::string )。 從概念上講,構造函數如下所示:

template <class Cont> cstring_span(Cont& c)

所以我猜當你從 lambda 返回時,會從v創建一個臨時對象,然后傳遞給cstring_span構造函數以提供非常量引用參數。 當然,一旦臨時清理干凈,您的cstring_span就會懸空。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM