首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用range-v3获得集合的所有权?

如何使用range-v3获得集合的所有权?
EN

Stack Overflow用户
提问于 2018-05-10 17:29:48
回答 1查看 229关注 0票数 2

我希望从表示STL集合上的视图的函数返回一个范围,如下所示:

代码语言:javascript
复制
auto createRange() {
    std::unordered_set<int> is = {1, 2, 3, 4, 5, 6};

    return is | view::transform([](auto&& i) {
        return i;
    });
}

但是,view::transform并不拥有is的所有权,所以当我运行它时,会出现未定义的行为,因为iscreateRange退出时被释放。

代码语言:javascript
复制
int main(int argc, char* argv[]) {
    auto rng = createRange();
    ranges::for_each(rng, [](auto&& i) {
        std::cout << std::to_string(i) << std::endl;
    });
}

如果我尝试std::move(is)作为输入,就会得到一个静态断言,表示不能将rvalue引用用作view的输入。是否有任何方法确保视图拥有集合的所有权?

编辑:一些附加信息

我想补充一些澄清的信息。我有一个数据流,data,它有一个视图,它将数据转换为一个结构,Foo,它看起来如下所示:

代码语言:javascript
复制
struct Foo {
    std::string name;
    std::unordered_set<int> values;
}

// Take the input stream and turn it into a range of Foos
auto foos = data | asFoo();

我想要做的是通过在所有值中分发名称来创建一个std::pair<std::string, int>的范围。我天真的尝试看起来是这样的:

代码语言:javascript
复制
auto result = data | asFoo() | view::transform([](auto&& foo) {
    const auto& name = foo.name;
    const auto& values = foo.values;
    return values | view::transform([name](auto&& value) {
        return std::make_pair(name, value);
    }
}) | view::join;

但是,这会导致未定义的行为,因为values被释放了。我能够解决这个问题的唯一方法是使values成为一个std::shared_ptr,并在传递给view::transform的lambda中捕获它,以保存它的生命周期。这似乎是一个不雅的解决方案。

我想我正在寻找的是一个观点,将采取的源代码集合所有权,但它看起来不像范围-v3有这一点。

或者,我可以使用一个好的老式for-循环创建分布式版本,但这似乎不适用于view::join

代码语言:javascript
复制
auto result = data | asFoo() | view::transform([](auto&& foo) {
    const auto& name = foo.name;
    const auto& values = foo.values;

    std::vector<std::pair<std::string, std::string>> distributedValues;
    for (const auto& value : values) {
        distributedValues.emplace_back(name, value);
    }

    return distributedValues;
}) | view::join;

即使这适用于view::join,我也认为范围和循环的混合隐喻也是不雅的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-10 17:40:21

视图不拥有它们所显示的数据。如果需要确保数据的持久性,则需要保留数据本身。

代码语言:javascript
复制
auto createRange() {
    //We're using a pointer to ensure that the contents don't get moved around, which might invalidate the view
    std::unique_ptr<std::unordered_set<int>> is_ptr = std::make_unique<std::unordered_set<int>>({1,2,3,4,5,6});
    auto & is = *is_ptr;
    auto view = is | view::transform([](auto&& i) {return i;});
    return std::make_pair(view, std::move(is_ptr));
}

int main() {
    auto[rng, data_ptr] = createRange();
    ranges::for_each(rng, [](auto&& i) {
        std::cout << std::to_string(i) << std::endl;
    });
}

另一种方法是确保为函数提供创建视图的数据集:

代码语言:javascript
复制
auto createRange(std::unordered_set<int> & is) {
    return is | view::transform([](auto&& i) {return i;});
}

int main() {
    std::unordered_set<int> is = {1,2,3,4,5,6};
    auto rng = createRange(is);
    ranges::for_each(rng, [](auto&& i) {
        std::cout << std::to_string(i) << std::endl;
    });
}

这两种解决方案都应该广泛地表示您的项目解决方案需要做什么。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50278395

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档