C++ C++;从未复制的原始数组构造向量

C++ C++;从未复制的原始数组构造向量,c++,memory,memory-management,c++20,c++11,C++,Memory,Memory Management,C++20,C++11,可以从原始指针构造一个向量而不复制吗 我知道向量本身具有所有权语义,它在构建时分配空间,并负责在销毁时释放内存。但这不是我想要的,我想要做的更像是一个适配器,它对底层数据没有所有权,只需要对数据进行一些包装,这样:1。更容易使用,2。做一些边界检查 我之所以想做这样的事情,是因为我的库的潜在用户可能有eigen、numpy、opencv或其他东西。我想采用一种更灵活的方式来传递数据,而无需复制。原始指针可以做到这一点,但我想做一些边界检查,否则其他人代码中的越界错误将最终导致我的库崩溃。如果我能

可以从原始指针构造一个向量而不复制吗

我知道向量本身具有所有权语义,它在构建时分配空间,并负责在销毁时释放内存。但这不是我想要的,我想要做的更像是一个
适配器
,它对底层数据没有所有权,只需要对数据进行一些包装,这样:1。更容易使用,2。做一些边界检查


我之所以想做这样的事情,是因为我的库的潜在用户可能有eigen、numpy、opencv或其他东西。我想采用一种更灵活的方式来传递数据,而无需复制。原始指针可以做到这一点,但我想做一些边界检查,否则其他人代码中的越界错误将最终导致我的库崩溃。如果我能创建这样一个没有所有权的容器,那么一切都将是完美的。

这很容易,只要你不需要所有权,就像你提到的那样。解决方案是使用类型擦除的连续序列。如果在某个时候你真的想要所有权,它会变得有点复杂。我已经在这个答案的底部添加了这方面的信息

非所有 如果您正在使用,那么可以使用--,它是一个围绕连续数据(如
std::vector
std::array
等)的非所有权包装器

如果您使用的是c++20之前的任何版本,则始终可以使用预先封装的
span
实现或基于该实现,例如从指南支持库或兼容的BackportC++实现

或者,也可以找到任何类似于
数组\u视图
的类型来完成相同的任务。有许多现有的开源解决方案可用于此目的

拥有 如果您确实需要所有权,那么将涉及更多的工作——特别是如果您希望数据来自不同的连续序列类型

为此,您将需要拥有类型擦除,并且在某个点上,将需要移动或复制一个向量——这两种方法之一。如果您可以允许客户端选择移动向量,这将比执行数据的深度复制便宜得多

要做到这一点,您需要有一个接口和一个类模板实现类型,所有这些都包装到一个漂亮的“向量”式API中。然后,捕获的数据可以间接地保存在类模板实现中,保存在
唯一的\u ptr
后面:

模板
类AnyVector
{
公众:
模板
显式AnyVector(容器和容器)
:m_容器{std::make_uniqueget(索引);
}
常量T&at(标准::大小索引)常量
{
如果(索引>=m_容器->大小()){
抛出std::超出范围{“AnyVector::at”};
}
返回m_容器->获取(索引);
}
std::size\u t size()常量
{
返回m_容器->大小();
}
私人:
//我们希望所有类型都遵循的接口
类接口
{
公众:
//使这个API尽可能深入
virtual~Interface()=默认值;
虚拟常量T&get(std::size\u T index)常量=0;
虚拟std::size\u t size()常量=0;
};
//接口的具体版本,就底层容器而言
模板
类具体:公共接口
{
公众:
模板
混凝土(隧道铺设和底层)
:m_底层{std::forward(底层)}
{
}
虚拟常量T&get(std::size_T index)常量重写{返回m_底层[index];}
virtual std::size_t size()const override{return m_underground.size();}
私人:
底层m_底层;
}
std::唯一的ptr m_容器;
};
仅当输入容器定义了
T::size()
T::operator[]
函数时,上述代码才起作用。如果您想要拥有的底层向量具有不同名称的函数,那么您需要更具创造性地解决这个问题——要么让用户使用traits(如type)明确指定,要么使用ADL中的非成员函数

在后一种情况下,可以通过以下方式实现:

std::size\u t size()常量覆盖
{
//ADL查找“大小”
退货尺寸(m_集装箱);
}

您必须编写自己的适配器,或者使用您最喜欢的搜索引擎查找适配器。您可以使用,而且添加绑定检查很容易。