6

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);

std::vector一般的に、配列からC ++を初期化することは可能ですか?このようなもの:

#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
4

6 に答える 6

8

あなたの質問が MATLAB/MEX とどのように関連しているかはわかりませんが、補足として、MATLAB がコピー オン ライト戦略を実装していることを知りたいと思うかもしれません。

これは、たとえば配列をコピーする場合、実際には一部のヘッダーのみがコピーされ、データ自体は 2 つの配列間で共有されることを意味します。そして、そのうちの 1 つが変更されると、データのコピーが実際に作成されます。

以下は、ボンネットの下で何が起こっているのかをシミュレートしたものです (この古い投稿から借用):

-----------------------------------------
>> 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 ...

これがあなたの質問に実際に答えているわけではないことはわかっていますが、概念が役立つかもしれないと思っただけです。

于 2009-11-14T23:39:02.303 に答える
6

std::vectorとはどちらublas::vectorもコンテナーです。コンテナーの要点は、コンテナーに含まれるオブジェクトのストレージと有効期間を管理することです。これが、それらを初期化するときに、所有するストレージに値をコピーする必要がある理由です。

C 配列は、サイズと場所が固定されたメモリ領域であるため、その性質上、コピーによってのみ値をコンテナーに取得できます。

C配列を多くのアルゴリズム関数への入力として使用できるので、初期コピーを回避するためにそれを行うことができますか?

于 2009-11-14T23:01:14.813 に答える
4

C配列からstd::vectorを簡単に初期化できます。

vector<int> v(pv, pv+10);
于 2009-11-14T22:38:14.470 に答える
4

uBLAS storage.hpp には、文書化されていないクラスが 2 つあります。これらのいずれかを使用して、ublas::vector のデフォルトのストレージ クラス (unbounded_array) を変更できます。

  • 最初のクラス、array_adaptor は、ublas::vector がコピー コンストラクターを呼び出すときにデータのコピーを作成しますが、まったく有用なクラスではありません。unbounded_array または bounded_array クラスでこれを行うには、単に適切なコンストラクターを使用したいと思います。
  • 2 番目の、shallow_array_adaptorは、データの参照のみを保持するため、vector を使用して C 配列を直接変更できます。残念ながら、いくつかのバグがあります。式を割り当てると、元のデータ ポインターが失われます。ただし、この問題を解決する派生クラスを作成できます。

ここにパッチと例があります:

// 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
于 2012-02-28T06:44:45.160 に答える
3

浅い配列アダプターを使用するという通常の提案は、私には一種の皮肉のようです-すべての参照カウントシバンを使用してshared_arrayに配置することになっているポインターを介して配列に単純にアクセスできるようにします(それは何にもなりません。配列を所有していない) さらに、データエイリアスの悪夢が発生します。実際、uBLAS にはストレージ ( ) の本格的な実装がありarray_adaptor、外部の c 配列でベクトルを使用できます。唯一の問題は、コピーを作成するベクター コンストラクターです。この優れた機能がライブラリで使用されていない理由は、私にはわかりませんが、とにかく、少し拡張を使用できます (実際には、通常の C++ 膨張で囲まれた 2 行のコードです)。

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 のサイズ変更メソッド (データの保持または破棄) を使用して、ベクトルを外部ストレージに動的にアタッチおよびデタッチできます。サイズを変更すると、ストレージから自動的に切り離され、通常のベクターになります。コンテナーからの代入は直接ストレージに入りますが、式からの代入は一時的に行われ、ベクトルはストレージから切り離されますnoalias()。これを防ぐために使用します。data_ はプライベート メンバーであり、デフォルトで新しい T[0] で初期化してから、外部配列に再割り当てする必要があるため、コンストラクターには小さなオーバーヘッドがあります。これを protected に変更し、コンストラクターで直接ストレージに割り当てることができます。

于 2012-06-23T22:05:18.557 に答える
2

以下に、構文的に便利な代入のための関数をいくつか示します (確かに初期化ではありません)。

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);
}
于 2012-01-06T02:52:09.853 に答える