我正在使用C ++ ublas库编写一个Matlab扩展,我希望能够从Matlab插件传递的C数组中初始化我的ublas向量。 如何在没有(为了提高效率)显式复制数据的情况下从C数组初始化ublas向量。我正在寻找以下代码行中的内容:
using namespace boost::numeric::ublas;
int pv[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };
vector<int> v (pv);
通常,是否可以从数组初始化C ++ std::vector
?像这样:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int pv[4] = { 4, 4, 4, 4};
vector<int> v (pv, pv+4);
pv[0] = 0;
cout << "v[0]=" << v[0] << " " << "pv[0]=" << pv[0] << endl;
return 0;
}
但初始化不会复制数据。在这种情况下,输出是
v[0]=4 pv[0]=0
但我希望输出相同,更新C数组会更改C ++向量指向的数据
v[0]=0 pv[0]=0
答案 0 :(得分:8)
我不确定你的问题与MATLAB / MEX有什么关系,但是请注意,你可能想知道MATLAB实现了写时复制策略。
这意味着当您复制数组时,实际上只复制了一些标题,而数据本身在两个数组之间共享。一旦修改了其中一个,就会实际制作一份数据。
以下是对引擎盖下可能发生的事情的一种模拟(借鉴于此old post):
-----------------------------------------
>> a = [35.7 100.2 1.2e7];
mxArray a
pdata -----> 35.7 100.2 1.2e7
crosslink=0
-----------------------------------------
>> b = a;
mxArray a
pdata -----> 35.7 100.2 1.2e7
crosslink / \
| / \ |
| | |
| | |
\ / | |
crosslink |
mxArray b |
pdata --------
-----------------------------------------
>> a(1) = 1;
mxArray a
pdata -----> (1) 100.2 1.2e7
crosslink=0
crosslink=0
mxArray b
pdata ------> 35.7 100.2 1.2e7 ...
我知道这并没有真正回答你的问题,我只是觉得你会发现这个概念很有用。
答案 1 :(得分:6)
std::vector
和ublas::vector
都是容器。容器的重点是管理其包含对象的存储和生命周期。这就是为什么在初始化它们时,它们必须将值复制到它们拥有的存储中。
C数组是大小和位置固定的内存区域,因此根据它们的性质,您只能通过复制将它们的值放入容器中。
你可以使用C数组作为许多算法函数的输入,所以也许你可以这样做以避免初始复制?
答案 2 :(得分:4)
您可以轻松地从C数组初始化std :: vector:
vector<int> v(pv, pv+10);
答案 3 :(得分:4)
uBLAS storage.hpp中有两个未记录的类。您可以使用其中一个更改ublas :: vector中的默认存储类(unbounded_array)。
这里有补丁和一个例子:
// BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR must be defined before include vector.hpp
#define BOOST_UBLAS_SHALLOW_ARRAY_ADAPTOR
#include <boost/numeric/ublas/vector.hpp>
#include <algorithm>
#include <iostream>
// Derived class that fix base class bug. Same name, different namespace.
template<typename T>
class shallow_array_adaptor
: public boost::numeric::ublas::shallow_array_adaptor<T>
{
public:
typedef boost::numeric::ublas::shallow_array_adaptor<T> base_type;
typedef typename base_type::size_type size_type;
typedef typename base_type::pointer pointer;
shallow_array_adaptor(size_type n) : base_type(n) {}
shallow_array_adaptor(size_type n, pointer data) : base_type(n,data) {}
shallow_array_adaptor(const shallow_array_adaptor& c) : base_type(c) {}
// This function must swap the values of the items, not the data pointers.
void swap(shallow_array_adaptor& a) {
if (base_type::begin() != a.begin())
std::swap_ranges(base_type::begin(), base_type::end(), a.begin());
}
};
void test() {
using namespace boost::numeric;
typedef ublas::vector<double,shallow_array_adaptor<double> > vector_adaptor;
struct point {
double x;
double y;
double z;
};
point p = { 1, 2, 3 };
vector_adaptor v(shallow_array_adaptor<double>(3, &p.x));
std::cout << p.x << ' ' << p.y << ' ' << p.z << std::endl;
v += v*2.0;
std::cout << p.x << ' ' << p.y << ' ' << p.z << std::endl;
}
输出:
1 2 3
3 6 9
答案 4 :(得分:3)
以下是一些用于语法上方便分配的函数(诚然不是初始化):
vector<int> v;
setVector(v, 3,
1, 2, 3);
matrix<int> m;
setMatrix(m, 3, 4,
1, 2, 3, 4,
11, 22, 33, 44,
111, 222, 333, 444);
功能:
/**
* Resize a ublas vector and set its elements
*/
template <class T> void setVector(vector<T> &v, int n, ...)
{
va_list ap;
va_start(ap, n);
v.resize(n);
for (int i = 0; i < n; i++) {
v[i] = va_arg(ap, T);
}
va_end(ap);
}
/**
* Resize a ublas matrix and set its elements
*/
template <class T> void setMatrix(matrix<T> &m, int rows, int cols ...)
{
va_list ap;
va_start(ap, cols);
m.resize(rows, cols);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
m(i, j) = va_arg(ap, T);
}
}
va_end(ap);
}
答案 5 :(得分:3)
使用浅阵列适配器的通常建议对我来说似乎有点讽刺 - 能够通过指针简单地访问一个数组,你应该将它放入一个带有所有引用计数shebang的shared_array中(这一点都没有了) ,因为你不拥有数组)以及数据别名的噩梦。
实际上,uBLAS有一个完全成熟的存储实现(array_adaptor
),它允许使用带有外部c数组的向量。唯一的问题是矢量构造函数,它可以复制。为什么库中没有使用这个好的功能是我的全部,但无论如何,我们可以使用一点扩展(它实际上是2行代码,包含普通的c ++膨胀)
template<class T>
class extarray_vector :
public vector<T, array_adaptor<T> >
{
typedef vector<T, array_adaptor<T> > vector_type;
public:
BOOST_UBLAS_INLINE
extarray_vector(size_type size, pointer p)
{ data().resize(size, p); }
template <size_type N>
BOOST_UBLAS_INLINE
extarray_vector(T (&a)[N])
{ data().resize(N, a); }
template<class V>
BOOST_UBLAS_INLINE
extarray_vector& operator = (const vector<T, V>& v)
{
vector_type::operator = (v);
return *this;
}
template<class VC>
BOOST_UBLAS_INLINE
extarray_vector& operator = (const vector_container<VC>& v)
{
vector_type::operator = (v);
return *this;
}
template<class VE>
BOOST_UBLAS_INLINE
extarray_vector& operator = (const vector_expression<VE>& ae)
{
vector_type::operator = (ae);
return *this;
}
};
你可以像这样使用它:
int i[] = {1, 4, 9, 16, 25, 36, 49};
extarray_vector<int> iv(i);
BOOST_ASSERT_MSG(i == &iv[0], "Vector should attach to external array\n");
iv[3] = 100;
BOOST_ASSERT(i[3] == 100);
iv.resize(iv.size() + 1, true);
BOOST_ASSERT_MSG(i != &iv[0], "And detach from the array on resize\n");
iv[3] = 200;
BOOST_ASSERT(i[3] == 100);
iv.data().resize(7, i, 0);
BOOST_ASSERT_MSG(i == &iv[0], "And attach back to the array\n");
BOOST_ASSERT(i[3] == 200);
您可以通过array_adaptor的resize方法(保留或丢弃数据)动态地将向量附加到外部存储并将其分离。调整大小时,它会自动从存储中分离并成为常规矢量。从容器中分配直接进入存储,但是从表达式分配是通过临时完成的,并且向量与存储分离,使用noalias()
来防止这种情况。构造函数的开销很小,因为data_是私有成员,我们必须使用新的T [0]默认初始化它,然后重新分配给外部数组。您可以将其更改为protected并直接在构造函数中分配给存储。