【问题标题】:function template with Segmentation fault具有分段错误的函数模板
【发布时间】:2020-01-28 14:01:57
【问题描述】:

我写拉函数来链接(读取->通过...->接收器)

template<typename T>
auto pull(T &&stream) {
    return std::forward<T>(stream);
}

// return void/read
// read -> sink
// read -> through
template<typename R, typename S>
auto pull(R &&read, S &sink) {
    return sink(std::forward<R>(read));
}

// return read
// read -> through -> ...
template<typename R, typename T, typename... Ts>
auto pull(R &&read, T &through, Ts &&... args) {
    return pull(through(std::forward<R>(read)), std::forward<Ts>(args)...);
}

读取函数,像这样,提供一个向量:

template<typename T>
auto values(T &begin, T &end) {
    return [&](bool abort, auto cb) {

        if (end != begin) {
            cb(false, *begin++);
        } else {
            cb(true, *begin);
        }
    };
}

通过函数,像这样:

template<typename T, typename M>
auto Map(M &&mapper) {

    return [&](auto &&read) {
        return [&](bool abort, auto cb) {
            read(abort, [&](bool end, T val) {
                if (end)
                    cb(true, val);
                else
                    cb(false, mapper(val));
            });
        };
    };
}

像这样的接收函数:

template<typename T, typename R>
auto log(R &&read) {

    std::function<void(bool, T)> more = [&](bool done, T val) {
        if (!done) {
            cout << val << endl;
            read(false, more);
        }
    };

    read(false, more);
}

然后在main函数中:

int main() {
    vector<int> vec;
    for (int i = 1; i < 4; i++) {
        vec.push_back(i);
    }
    auto begin = vec.begin();
    auto end = vec.end();

    auto vals = values(begin, end);
    auto mapper = [&](int val) { return val * 2; };
    auto timesTwo = Map<int>(mapper);
    auto newVals1 = pull(vals, timesTwo, timesTwo);
    auto newVals2 = pull(vals, timesTwo);
    auto logInt = [&](auto read) { log<int>(read); };

    //pull(newVals1, logInt); // Segmentation fault, how to correct `pull` function to make this run right
    pull(newVals2, logInt); // ok

    return 0;
}

pull(newVals2, logInt); 工作正常,

但是pull(newVals1, logInt);抛出Segmentation fault;

我想让pull(newVals1, logInt); 正常工作。

我想,可能是pull函数中的一些错误,但我不知道在哪里,谁能帮助我?

code example

【问题讨论】:

  • Lambda 通过 return 或使用 std::function 通过引用捕获所有信息来逃避其范围通常是一个危险信号
  • 肯定还有另一个问题我还没有解决,但一个问题是您在 values 的 lambda 中取消引用 else 子句中的 end 迭代器。
  • SegFault 意味着你毁了你的记忆!我之前被骂过!但那是真正的问题。我希望这会有所帮助!

标签: c++ c++11 c++14


【解决方案1】:

我想我已经弄清楚了哪里出了问题。正如之前的一位用户评论的那样,在通过引用捕获超出其范围的 lambda 时,您需要非常谨慎。

具体来说,我认为问题出在 Map 函数内部,其中内部 lambda 通过引用捕获了 read 参数。如果使用左值参数调用它时,它的作用域将超过 lambda,这很好,就像在单调用案例 pull(vals, timesTwo) => timesTwo(vals) 中的情况一样,但在双调用案例 pull(vals, timesTwo, timesTwo) => @987654326 中@,传递给timesTwo 的外部调用的参数是一个右值,因此read 引用对象立即悬空。

另一个不相关的问题:在values 函数中,lambda 中的else 子句将取消引用结束迭代器。我不相信你依赖它的返回值,它似乎按预期工作,但它是未定义的行为。

【讨论】:

  • 我也不确定vals 在一次使用后基本上被消耗是不是故意的,因为begin 迭代器是通过引用捕获并递增直到它等于end
  • 我认为你是对的,bug如何纠正,你能帮帮我吗?
  • @langyu 我发现的三个错误中您要问的是哪一个?当然,您可以自己解决其中的一些问题。
  • case pull(vals, timesTwo, timesTwo) =&gt; timesTwo(timesTwo(vals)), read 引用对象立即悬空 -> 我想修复这个错误,但我不知道如何修复它,我花了 3 天时间......你能帮忙我?
  • @langyu 使你所有的 lambda 捕获显式(没有 [&amp;] - 列出你想要捕获的所有变量),仔细决定哪些应该是引用,哪些是值。特别是,read 需要通过特定 lambda 中的值来捕获以避免此段错误,但还有其他一些仅在特定用例中起作用,但通常不能保证。
猜你喜欢
  • 1970-01-01
  • 2015-07-18
  • 2011-12-14
  • 2020-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多