如何使用 gsl::span 并指示所有权?

ein*_*ica 5 c++ cpp-core-guidelines guideline-support-library

我想写一个函数:

  1. 接受一个指针作为参数
  2. 以长度作为参数
  3. 拥有指针指向的内存(例如,它可能会释放它,或者在某些数据结构中为其构造一个 unique_ptr 等)

现在,如果我想要 1+2,我就会使用gsl::span. 如果想要 1+3 我会使用owner<T*>. 但当我想要这三个时我该怎么办?我应该通过吗owner<gsl::span<T>>?还有别的事吗?

笔记:

  • 您可能不会假设指针位于堆中。
  • std::vector要求太多。该函数不应该要求调用者构造一个std::vector.

Chr*_*rew 1

一种选择是定义您自己的抽象基类来封装数据。就像是:

template<typename T>
class DataHolder {
public:
  virtual ~DataHolder() = default;
  virtual gsl::span<T> get() const = 0;
};
Run Code Online (Sandbox Code Playgroud)

那么你的函数可能看起来像:

void foo(std::unique_ptr<DataHolder<int>> data) {
  if (!data)
    return;
  for (auto v : data->get())
    std::cout << v << " ";
}
Run Code Online (Sandbox Code Playgroud)

然后,调用者可以使用他们想要的任何容器来实现基类。多态性会产生很小的成本,但不是基于每个元素。

如果您不想为多态性付费,也许您可​​以让您的函数接受模板参数。

template<typename DataHolder>
void foo(DataHolder data) {
  for (auto v : data())
    std::cout << v << " ";
}
Run Code Online (Sandbox Code Playgroud)

其中隐式接口DataHolder可以通过以下方式满足:

struct VectorHolder {
    std::vector<int> data;
    gsl::span<const int> operator()() const { return data; }
};
Run Code Online (Sandbox Code Playgroud)

或者如果您确实不想使用vector. 你可以使用这样的东西(按照@utnapistim的建议):

struct ArrayHolder {
    std::unique_ptr<int[]> data;
    ptrdiff_t              length;
    gsl::span<const int> operator()() const { return {data.get(), length}; }
};
Run Code Online (Sandbox Code Playgroud)