让范围视图拥有一个包含其所需状态的shared_ptr可以吗

Is it okay to let a range view own a shared_ptr containing state it needs?

本文关键字:shared ptr 状态 视图 范围 拥有 有一个 包含其      更新时间:2024-09-27

基本上,我试图绕过以下不适用于range-v3范围的事实:(这是一个玩具示例,但说明了问题。(

namespace rv = ranges::views;
auto bad_foo() {
std::vector<int> local_vector = { 23, 45, 182, 3, 5, 16, 1 };
return local_vector |
rv::transform([](int n) {return 2 * n; });
}
int main() {
for (int n :bad_foo()) {
std::cout << n << " ";
}
std::cout << "n";
return 0;
}

以上内容不起作用,因为我们返回的视图引用了bad_foo返回时将超出范围的数据。

我想做的是将向量存储在共享指针中,这样范围视图将保持共享指针的活动状态。请注意,这个想法的明显版本不起作用,即

auto still_bad_foo() {
auto shared_vector = std::make_shared<std::vector<int>>(
std::initializer_list{ 23, 45, 182, 3, 5, 16, 1 }
);
return *shared_vector |
rv::transform([](int n) {return 2 * n; });
}

仍然失败,因为CCD_ 2实际上没有被范围视图捕获。我们想要做的是强制范围视图拥有共享指针。

以下内容对我来说似乎有效。

auto good_foo() {
auto shared_vector = std::make_shared<std::vector<int>>(
std::initializer_list{ 23, 45, 182, 3, 5, 16, 1 }
);
return rv::single(shared_vector) |
rv::transform([](auto ptr) {  return rv::all(*ptr); }) |
rv::join |
rv::transform([](int n) {return 2 * n; });
}

我们使用single将共享指针转换为单个项目范围视图,通过在transform中取消引用指针并用all将向量封装在范围中,将单个项目转换为int范围,从而生成范围视图的组合,然后通过join将其压平。

我的问题是,以上内容真的安全吗?如果是,是否有同样想法的不那么冗长的版本?

编辑:将问题更新为关于range-v3 ranges@康桓瑋已经提醒我,只要不要求拥有的范围视图是可复制的,这个问题就不是C++20范围的问题。

基本上,我试图绕过以下事实不起作用:(这是一个玩具例子,但说明了问题使用范围-v3,但这个问题也适用于标准范围(

如果您使用标准<ranges>,那么您不必担心这一点,只需将vector移动到管道中,即可将vector的所有权移动到owning_view

auto not_bad_foo() {
std::vector<int> local_vector = { 23, 45, 182, 3, 5, 16, 1 };
return std::move(local_vector) | // <- here
std::views::transform([](int n) {return 2 * n; });
}

演示

如何捕获lambda中的向量以延长其使用寿命?

auto create_foo() {
std::vector<int> local_vector = { 23, 45, 182, 3, 5, 16, 1 };
return [captured_vector = std::move(local_vector)]() {
return captured_vector | rv::transform([](int n) {return 2 * n; });
};
}
int main() {
for (int n : create_foo()()) {
std::cout << n << " ";
}
std::cout << "n";
}