使用std :: vector作为原始内存的视图 [英] Using std::vector as view on to raw memory

查看:49
本文介绍了使用std :: vector作为原始内存的视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用一个外部库,该库有时会给我一个指向整数和大小数组的原始指针.

I'm using a external library which at some point gives me a raw pointer to an array of integers and a size.

现在,我想使用 std :: vector 来就地访问和修改这些值,而不是使用原始指针来访问它们.

Now I'd like to use std::vector to access and modify these values in place, rather than accessing them with raw pointers.

以下是一个人工例子,可以解释这一点:

Here is an articifial example that explains the point:

size_t size = 0;
int * data = get_data_from_library(size);   // raw data from library {5,3,2,1,4}, size gets filled in

std::vector<int> v = ????;                  // pseudo vector to be used to access the raw data

std::sort(v.begin(), v.end());              // sort raw data in place

for (int i = 0; i < 5; i++)
{
  std::cout << data[i] << "\n";             // display sorted raw data 
}

预期输出:

1
2
3
4
5

原因是我需要对该数据应用< algorithm> 中的算法(排序,交换元素等).

The reason is that I need to apply algorithms from <algorithm> (sorting, swaping elements etc.) on that data.

另一方面,更改该矢量的大小永远不会更改,因此不需要 push_back erase insert 在那个向量上.

On the other hand changing the size of that vector would never be changed, so push_back, erase, insert are not required to work on that vector.

我可以基于库中的数据构造一个向量,使用修改该向量并将数据复制回库中,但这是我要避免的两个完整副本,因为该数据集可能确实是大.

I could construct a vector based on the data from the library, use modify that vector and copying the data back to to library, but that would be two complete copies that I'd like to avoid as the data set could be really big.

推荐答案

问题是 std :: vector 必须从初始化它的数组中复制元素,因为它具有它包含的对象的所有权.

The problem is that std::vector has to make a copy of the elements from the array you initialize it with as it has the ownership of the objects it contains.

为避免这种情况,可以对数组使用 slice 对象(即类似于 std :: string_view std :: string ).您可以编写自己的 array_view 类模板实现,其实例是通过使用指向数组第一个元素和数组长度的原始指针构造的:

To avoid this, you can use a slice object for an array (i.e., similar to what std::string_view is to std::string). You could write your own array_view class template implementation whose instances are constructed by taking a raw pointer to an array's first element and the array length:

#include <cstdint>

template<typename T>
class array_view {
   T* ptr_;
   std::size_t len_;
public:
   array_view(T* ptr, std::size_t len) noexcept: ptr_{ptr}, len_{len} {}

   T& operator[](int i) noexcept { return ptr_[i]; }
   T const& operator[](int i) const noexcept { return ptr_[i]; }
   auto size() const noexcept { return len_; }

   auto begin() noexcept { return ptr_; }
   auto end() noexcept { return ptr_ + len_; }
};

array_view 不存储数组;它只是持有一个指向数组开头和该数组长度的指针.因此, array_view 对象的构造和复制都很便宜.

array_view doesn't store an array; it just holds a pointer to the beginning of the array and the length of that array. Therefore, array_view objects are cheap to construct and to copy.

由于 array_view 提供了 begin() end()成员函数,因此您可以使用标准库算法(例如,> std :: sort std :: find std :: lower_bound 等)

Since array_view provides the begin() and end() member functions, you can use the standard library algorithms (e.g., std::sort, std::find, std::lower_bound, etc.) on it:

#define LEN 5

auto main() -> int {
   int arr[LEN] = {4, 5, 1, 2, 3};

   array_view<int> av(arr, LEN);

   std::sort(av.begin(), av.end());

   for (auto const& val: av)
      std::cout << val << ' ';
   std::cout << '\n';
}

输出:

1 2 3 4 5


改为使用 std :: span (或 gsl :: span )

上面的实现公开了 slice对象背后的概念.但是,从C ++ 20开始,您可以直接使用 std :: span .在任何情况下,自C ++ 14起,您都可以使用 gsl :: span


Use std::span (or gsl::span) instead

The implementation above exposes the concept behind slice objects. However, since C++20 you can directly use std::span instead. In any case, you can use gsl::span since C++14.

这篇关于使用std :: vector作为原始内存的视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆