C 样式数组与 std::库接口的数组
C-style array vs std::array for library interface
我想编写一个带有提供读取函数的接口的库。 C 样式数组容易出错,但允许传递任何大小的缓冲区。 C++数组更安全,但强制要求以一定大小构造。
// interface.h
// C-style array
int read (std::uint8_t* buf, size_t len);
// C++ array
int read (std::array<std::uint8_t, 16>& buff)
我怎样才能两全其美?
我在考虑函数模板,但对于库接口来说似乎并不实用。
template <size_t N>
int read (std::array<std::uint8_t, N>& buf);
编辑std::vector
可能是一个很好的候选者,但如果我们认为char*
和std::array
没有动态分配。
编辑我非常喜欢gsl::span
的解决方案。我被困在 C++14 所以没有std::span
.我不知道使用第三个库 (gsl) 是否会成为问题/允许。
编辑我不认为使用char
而不是另一种类型会对答案产生一些影响,所以更清楚的是操纵字节。我把char
改成std::uint8_t
编辑由于 C++11 保证退货std::vector
将移动而不是复制,因此退货std::vector<std::uint8_t>
是可以接受的。
std::vector<std::uint8_t> read();
您可以执行标准库的操作:使用一对迭代器。
template <typename Iter> int read(Iter begin, Iter end)
{
// Some static assets to make sure `Iter` is actually a proper iterator type
}
它为您提供了两全其美的优势:安全性略高,并且能够读取缓冲区的任意部分。此外,它还允许您读取非应急容器。
我怎样才能拥有两个世界中最好的?
通过使用std::vector
:
- 就像
std::array
s一样:它比C阵列更安全。 - 像 C 数组一样:它允许您使用必须能够接受任意大小数组的函数。
编辑:std::vector
并不一定意味着动态分配(如动态存储持续时间)。这取决于所使用的分配器。您仍然可以提供用户指定的堆栈分配器。
我会违背原则,说对于read
类型的函数,void*
指针和大小可能是最好的选择。这是世界各地任何无格式读取函数所采用的方法。
为什么不使用gsl::span
,它的目的是消除一系列连续对象的指针和长度参数对?这样的东西会起作用:
int read(gsl::span<uint8_t> buf)
{
for (auto& elem : buf)
{
// Do whatever with elem
}
}
唯一的问题是,不幸的是,gsl::span
不是C++标准的一部分(也许它可能在 C++20 中),安装它需要一个像 GSL-lite 这样的库
。以下是更多关于span
的细节,来自赫伯·萨特。
你真的关心底层容器的类型吗?
template<typename Iterator>
int read_n(Iterator begin, size_t len);
假设此函数返回读取的元素数,我也会将返回类型更改为size_t
。
char *dyn = new char[20];
char stat[20];
std::vector<char> vec(20);
read(dyn, 20);
read(stat 20);
read(vec.begin(), 20);
我认为在设计lib的界面时,您需要考虑使用它的位置。
带有带有"char *"的 C 接口的库可用于多种语言(C、C++ 等)。使用 std::array 会限制库的潜能客户端。
第三个可能的变体:
struct buf_f allocBuf();
int rmBuf( struct buf_t b );
int read( struct buf_f b );
char * bufData( struct buf_f b );
size_t bufSize( struct buf_f b );
当然,它可以以更优雅的方式用C++重写。
您可以使用 make 包装器函数,该函数是委托给 C 接口函数的模板函数:
int read(std::uint8_t* buf, size_t len);
template <size_t N>
int read(std::array<std::uint8_t, N>& buf)
{
return read(buf.data(), buf.size());
}
当我需要通过 C ABI 进行某些操作时,我发现这样的结构很有用,但不想失去C++提供的一些舒适感,因为模板函数是作为库客户端代码的一部分编译的,不需要与 C ABI 兼容,而模板函数调用的函数与 C ABI 兼容
只需返回一个std::vector<uint8_t>
,除非这是一个 DLL,在这种情况下,请使用 C 样式接口。
注意:问题从char
更改为uint8_t
后,答案从std::string
更改为std::vector
。
- Mongodb c++驱动程序:如何查询元素的数组
- 将数组的地址分配给变量并删除
- 从C++本机插件更新Vector3数组
- COM 接口 c# 封送数组数组
- 如何模板化堆栈分配的多态指针数组到接口,包括派生类型的相应点?
- C/C++中数组结构和数组结构的通用接口
- 静态声明专用类的接口指针数组
- C 样式数组与 std::库接口的数组
- 将从接口派生的类的实例添加到接口指针数组中
- 无法更改调用接口时的initialize数组
- 如何使用结构体作为接口从函数返回指向数组的指针
- 更快地以数组形式返回数据的c++接口
- 纯虚类(接口)和继承它的对象的内部数组分配
- Marshalas UnManagedType用于接口数组
- 哪个接口将字符串、数组和其他类型复制到相同类型的实例
- 如何在构造函数中创建接口数组
- 将const double[][]数组作为参数传递给double**接口
- hdf5c++接口:编写动态二维数组
- 当编组接口数组从.net到c++时抛出ExecutionEngineException
- C++策略设计模式,制作一个接口数组