繁体   English   中英

如何转换向量 <vector<int> &gt; int **而无需重建数组?

[英]How to convert a vector<vector<int>> to int** without rebuilding the array?

我不太喜欢使用指针,而且我总是使用stl工具。 我陷入了这种情况,我需要将int **传递给需要使用2d数组int的third_party函数。 我编写了以下函数,该函数创建一个int * s向量来完成这项工作。 我的问题是,假设third_party函数不更改数组的结构并且仅访问数据条目,这样做是否安全? 有一个更好的方法吗?

这是函数def:

void ConvertVectorVectorToIntStarStar(const std::vector<std::vector<int> >& v,vector<int*>* a) {
  assert(a);
  int n = v.size();
  a->resize(n);
  for(int i = 0; i < n; ++i)
    (*a)[i] = (int*)(&v[i][0]);
}

这是用法:

  vector<int*> p;
  ConvertVectorVectorToIntStarStar(v, &p);
  int** a = &p[0];
  third_party_function(a);

如何将vector<vector<int>>转换为int**

您不能简单地将其转换。

vector<int>vector<int>的内部布局与int*数组令人难以置信地不兼容。 :-)

这是您的类型:

vector<vector<int>> v{{ 1, 2, 3 }, { 1, 2, 3 }, { 1, 2, 3 } };
int (*a)[] = { new int[3], new int[3], new int[3] };

您会注意到的第一件事是aint (*)[]而不是int** 当使用a它将衰减为int** int[][] 不会这样做

让我们获取一级指针:

vector<int>* ptr1 = &v[0];
int**        ptr2 = &a[0];

现在让我们看一下存储:

  • ptr1[0]vector<int>
  • ptr2[0]是一个int*

显然,这些绝不是同一件事。 甚至无需进一步操作,内存布局就已经不同。 这意味着您不能只是“获取”向量数据的int**


但是 ,如果您不介意从头开始构建最外面的“索引”数组,那么您的方法基本上是正确的。 这似乎不是您要遵循的零步骤流程。


代替所有这些,我的建议是使用二维索引访问语义包装vector<int> (长度Width×Height)。 然后,您可以根据需要对整个数据缓冲区使用int*

感谢Freenode ## c ++

template<typename T>
struct matrix
{
   matrix(unsigned m, unsigned n)
      : m(m), n(n), vs(m*n)
   {}

   T& operator()(unsigned i, unsigned j)
   {
      return vs[i + m * j];
   }

private:
   unsigned m, n;
   std::vector<T> vs;
};

/* column-major/opengl: vs[i + m * j], row-major/c++: vs[n * i + j] */

如果需要演员表,那是不对的:

(*a)[i] = (int*)(&v[i][0]);

这应该真的读

(*a)[i] = const_cast<int*>(v[i].data());

否则,代码看起来就可以正常工作了: std::vector<T>中的元素是连续的。

代替当前代码...

void ConvertVectorVectorToIntStarStar(const std::vector<std::vector<int> >& v,vector<int*>* a) {
  assert(a);
  int n = v.size();
  a->resize(n);
  for(int i = 0; i < n; ++i)
    (*a)[i] = (int*)(&v[i][0]);
}

我建议你做……

vector<int*> IntStarStarFrom( std::vector<std::vector<int>>& v)
{
    int const n = static_cast<int>( v.size() );
    assert( n > 0 );
    vector<int*> a( n );

    for(int i = 0; i < n; ++i)
    {
        assert( v[i].size() > 0 );
        a[i] = &v[i][0];
    }
    return std::move( a );
}

免责声明:现成的袖珍代码,不会被编译器之手触及。

这些断言表达了相关的安全问题。

保证向量的缓冲区是连续的,但是IIRC在其大小为0时对向量进行索引是未定义行为。

修改了用法代码以使用建议的功能替换:

vector<int*> p = IntStarStarFrom( v );
int** const a = &p[0];
third_party_function( a );

或如Mark Ransom在评论中所述,您现在可以在一行代码中完成此操作:

third_party_function(IntStarStarFrom(v).data());
std::vector<std::vector<int> > vt;
// some code with vt..

std::vector<int *> vtp;
for (const std::vector<int> &vtr : vt)
    vtp.push_back(const_cast<int *>(vtr.data()));

我还没有测试,但我认为我做得很好

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM