C++ C++;带有std::span的Ranges-v3:从函数返回范围视图时中间对象的所有权
我对Eric Niebler的ranges-V3库(到目前为止我都很喜欢!)是一个完全的初学者,但是在从函数返回范围时遇到了一些问题。我想我发现了这个问题,但是对于ranges API在本例中的默认行为感到有点惊讶。由于我没有在其他地方找到任何关于这个问题的参考资料,而且花费了我相当多的时间,所以我把我的问题写得有点广泛,希望这能对将来的其他人有所帮助 问题出现在下面的最小示例中,这会导致未定义的行为C++ C++;带有std::span的Ranges-v3:从函数返回范围视图时中间对象的所有权,c++,range-v3,C++,Range V3,我对Eric Niebler的ranges-V3库(到目前为止我都很喜欢!)是一个完全的初学者,但是在从函数返回范围时遇到了一些问题。我想我发现了这个问题,但是对于ranges API在本例中的默认行为感到有点惊讶。由于我没有在其他地方找到任何关于这个问题的参考资料,而且花费了我相当多的时间,所以我把我的问题写得有点广泛,希望这能对将来的其他人有所帮助 问题出现在下面的最小示例中,这会导致未定义的行为 #include <iostream> #include "range/v3/al
#include <iostream>
#include "range/v3/all.hpp"
#include "nonstd_span.h"
auto from_span() {
// make this static for the array to persist after the fct returns
static int my_array[10] = { 1,2,3,4,5,6,7,8,9,10 };
auto my_span = nonstd::span<int>(my_array, 10);
return ranges::views::all(my_span);
}
int main() {
std::cout << from_span() << std::endl;
return 0;
}
span
不是任务的正确工具吗?它似乎是为像这样的用例创建的?这个范围库可能不知道nonsd::span
是一个视图。您需要通过专门化ranges::enable_view
来判断它。如果没有这一点,范围库会认为它类似于一个向量,当您将它的左值传递给views::all
时,会返回一个引用本地span
对象的视图,而不是span
的副本
在最近的过去,range-v3会使用一种启发式方法(正确地)猜测span
是一个视图,而您的代码就可以正常工作了。它由C++委员会更改了每个请求,而不喜欢启发式。公平地说,它有时会猜错。运行第一个代码段时会发生什么?我不确定那里是否有UB。当我使用ranges::span
时,它似乎对我来说很有用。在我的系统上,它似乎大部分时间都在工作,即打印[1,2,3,4,5,6,7,8910]
。有时分段错误
,有时空列表[]
。我是如何意识到有一个问题的,那就是在我使用的实际代码中,returnranges::any_视图(ranges::views::all(my_span))代码>以强制转换为通用类型。在这种情况下,它通常会打印出非常随机的数字,大多数时候我认为错误和任何视图有关。@cigien谢谢,这很有趣,我尝试了gcc10.1的godbolt(我认为它完全支持C++20),但无法使std::span正常工作。我需要一点时间来追踪我的系统的差异。还不确定,我在系统上给出的非常简单的示例总是需要一些时间来强制执行奇怪的行为。在这种特殊情况下,您可以只返回范围::视图::全部(我的数组)
,而不使用span
。谢谢Eric,这充分解释并解决了这个问题。当我写这个问题时,我没有意识到ranges::span
,一旦我切换到这个问题,整个问题就不会发生。同时,对图书馆的巨大感谢,我的C++代码将开始看起来非常不同。
auto from_span() {
using namespace ranges;
static int my_array[10] = { 1,2,3,4,5,6,7,8,9,10 };
auto span_ptr = std::make_unique<nonstd::span<int>>(my_array, 10);
return std::make_tuple(views::all(*span_ptr), std::move(span_ptr));
}
int main() {
auto [rng, my_span_ptr] = from_span();
std::cout << rng << std::endl;
return 0;
}