【问题标题】:Accessing a vector<vector<int>> as a flat array将 vector<vector<int>> 作为平面数组访问
【发布时间】:2012-10-20 22:53:42
【问题描述】:

对于这个数组:

vector<vector<int> > v;

v.push_back(vector<int>(0));
v.back().push_back(1);
v.back().push_back(2);
v.back().push_back(3);
v.back().push_back(4);

我可以很容易地输出 {1, 2, 3, 4}:

cout << v[0][0] << endl;
cout << v[0][1] << endl;
cout << v[0][2] << endl;
cout << v[0][3] << endl;

要以平面数组的形式访问它,我可以这样做:

int* z = (int*)&v[0].front();

cout << z[0] << endl;
cout << z[1] << endl;
cout << z[2] << endl;
cout << z[3] << endl;

现在,如何将多维向量作为平面多维数组访问?我不能使用与访问一维向量相同的格式:

// This does not work (outputs garbage)
int** n = (int**)&v.front();

cout << n[0][0] << endl;
cout << n[0][1] << endl;
cout << n[0][2] << endl;
cout << n[0][3] << endl;

我发现的解决方法是这样做:

int** n = new int* [v.size()];

for (size_t i = 0; i < v.size(); i++) {
   n[i] = &v.at(i).front();
}

cout << n[0][0] << endl;
cout << n[0][1] << endl;
cout << n[0][2] << endl;
cout << n[0][3] << endl;

有没有办法像平面 c 样式数组一样访问整个多维向量,而不必在访问数据之前动态分配数据上方的每个维度?

速度在实施中并不重要,维护的清晰性至关重要。多维向量非常适合存储数据。但是,我还想在 SDK 中将数据公开为平面 c 样式数组,以便其他语言可以轻松访问它。这意味着将向量公开为 STL 对象是不行的。

我提出的解决方案可以很好地满足我的需求,因为我只在处理结束时评估一次数组以“展平”它。但是,有没有更好的方法来解决这个问题?或者我是否已经在不重新实现我自己的数据结构的情况下尽我所能做到最好(矫枉过正,因为我的扁平化代码只有几行)。

感谢您的建议,朋友们!

【问题讨论】:

  • 你知道第二个尺寸吗,我的意思是所有vector&lt;int&gt;元素的尺寸都应该一样吗?

标签: c++ vector std multidimensional-array flat


【解决方案1】:

vector 的缓冲区通常是动态分配的。

这意味着当您拥有vectors 中的vector 时,对于内部缓冲区,您拥有类似于指针数组的东西,每个指针都指向一个数组。

如果您需要在相同数据的 1D 和 2D 视图之间切换,最简单的可能就是定义一个 2D 数组类,如下所示(即兴发挥):

typedef ptrdiff_t Size;
typedef Size Index;

template< class Item >
class Array2D
{
private:
    std::vector< Item > items_;
    Size                width_;
    Size                height_;

    Index indexFor( Index const x, Index const y )
    { return y*width_ + x; }

public:
    Size width() const { return width_; }
    Size height() const { return height_; }

    Item& operator()( Index const x, Index const y )
    { return items_[indexFor( x, y )]; }

    Item const& operator()( Index const x, Index const y ) const
    { return items_[indexFor( x, y )]M; }

    Size bufferSize() const { return width_*height_; }
    Item* buffer() { return &items_[0]; }
    Item const* buffer() const { return &items_[0]; }

    Array2D( Size const w, Size const h )
        : items_( w*h )
        , width_( w )
        , height_( h )
    {}
};

然后你可以做类似的事情

Array2D< int >  a( 4, 3 );

for( Index y = 0;  y < a.height();  ++y )
{
    for( Index x = 0;  x < a.width();  ++x )
    {
        foo( a( x, y ) );
    }
}

Array2D< int >  a( 4, 3 );

int* const pb = a.buffer();
for( Index i = 0;  i < a.bufferSize();  ++i )
{
    foo( pb[i];
}

【讨论】:

  • +1:已更改。你正在在这个专栏中占主导地位,最后发现了这一点。无论哪种方式都完全正确。
【解决方案2】:

嗯,你不能,因为虽然向量可以保证将它们的元素存储在连续的内存中,但向量的向量并不能保证与 2D C 样式数组相同的存储布局。

所以不,这是不可能的,我会更进一步说int* z = (int*)&amp;v[0].front(); 实在是太丑了。

【讨论】:

    【解决方案3】:

    如果您的一维向量 (std::vector&lt;int&gt;) 大小相同 - 则保留向量原始数组:

    typedef int ARRAY[6];
    std::vector<ARRAY> yourVector; 
    

    如果它们的大小不相同 - 那么你就有真正的问题,因为每个 std::vector&lt;int&gt; 占用了连续的内存区域,但这些区域并不连续。就像在这个原始的 C 数组中一样:

    int** a = new int*[3];
    a[0] = new int[4];
    a[1] = new int[5];
    

    a 不指向大小为(4+5)*sizeof(int) 的连续内存...

    【讨论】:

      【解决方案4】:

      现在,如何将多维向量作为平面多维数组访问?

      你不能。

      您可以将vector&lt;int&gt; 作为int[] 访问的原因是因为布局相同。 vector&lt;vector&lt;int&gt;&gt;的内存布局与int*[]的布局不同,也就是说你不能像int*[]一样访问它。

      如果您无法避免通过int*[] 访问数据,那么您所做的就是分配int* 的数组并用指向向量的指针填充它,这是您能做的最好的事情。不过,如果您一开始就可以避免这样做会更好。

      您可能希望为int*[] 使用异常安全持有者。您也可能不需要使用vector::at(),并且您可能会考虑是否需要处理向量之一为空的情况。在这里,我使用 C++11 特性解决了这些问题。

      std::unique_ptr<int*[]> n(new int* [v.size()]);
      transform(begin(v), end(v), n.get(), [](std::vector<int> &i) { return i.data(); });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-11-11
        • 1970-01-01
        • 2023-01-20
        • 1970-01-01
        • 1970-01-01
        • 2013-03-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多