我正在编写一些状态机代码,不同的类负责不同类型的任务,所有这些任务都在获取数据。完成数据采集后,需要将数据发送出去。负责的班级看起来像这样:
class SendBuffer {
std::uint8_t* get_position(/*some arguments to determine buffer*/) {
return &buffer[/*at determined location*/];
}
private:
std::array<std::uint8_t, MAX_SIZE> buffer;
};
当然,这根本不安全,因为返回的指针没有缓冲区中专用切片的长度等信息
我考虑返回
std::span<std::uint8_t>
而不是原始指针,但我想知道这里的最佳实践是什么。
使用
std::span
(cppreference) 是正确的方法。正如评论中提到的,它可以从视图初始化。另外,span
的成员函数提供了有用的实用程序。如果出现问题,可以使用 subspan(offset, extent)
函数将单个值作为范围返回。
std::span get_position(std::size_t i) {
return std::span(buffer).subspan(i, 1);
}
对于单个值,返回引用可能更有用。但对于缓冲区的子范围,
span
的subspan
、first
和last
很方便。一些例子:
std::array<T, N> buffer;
std::span buffer_view{buffer}; // of type std::span<T, N>
buffer_view.subspan(a) // range from indices [a, end)
buffer_view.subspan(a, b) // range from indices [a, a+b)
buffer_view.subspan(a).first<B>() // range from indices [a, a+B) with compile time B
// thus returns std::span<T, B>
请注意
subspan
、first
和 last
具有静态和动态重载
buffer_view.subspan<A, B>() // std::span<T, B>
buffer_view.subspan(a, b) // std::span<T, std::dynamic_extent>
buffer_view.first<C>() // std::span<T, C>
buffer_view.first(c) // std::span<T, std::dynamic_extent>
buffer_view.last<D>() // std::span<T, D>
buffer_view.last(d) // std::span<T, std::dynamic_extent>
其中大写字母表示编译时间常数,小写字母也可以表示运行时大小。