【问题标题】:vector to array and array size in c++C++中的向量到数组和数组大小
【发布时间】:2017-01-04 15:20:06
【问题描述】:

我有一个结构:

struct xyz{
    int x,y,z;
};

我初始化了一个struct xyz 类型向量:

for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < N; j++)
        {
            for (int k = 0; k < N; k++)
            {
                v.x=i;
                v.y=j;
                v.z=k;
                vect.push_back(v);
            }
        }
    }

然后我想将该向量转换为数组,因为数组的操作速度比向量快 2 倍,所以我这样做了

 xyz arr[vect.size()];
 std::copy(vect.begin(), vect.end(), arr);

当我运行这个程序时,它显示了分段错误,我认为这是因为vect.size() 太大。 所以我想知道有没有办法将那个大尺寸的向量转换为数组而没有这个问题。 感谢您的帮助

【问题讨论】:

  • 您需要使用堆 (new),因为直到运行时才知道向量的大小。
  • 你从哪里得到因为数组的操作比向量快2倍?正确使用的向量在速度方面应该与数组几乎相同。
  • 1) VLA (xyz arr[vect.size()];) 是非标准 C++ 2) 你觉得呢?您是否尝试过 anything 自行解决问题(例如调试器)? 3) 我想将该向量转换为数组,因为数组的操作速度比向量快 2 倍你从哪里读到这个废话?
  • 您要么知道编译时xyz 实例的数量,要么您不知道。如果您这样做,请使用std::array,如果您不这样做,请使用std::vector。混合这些容器没有任何好处。

标签: c++ arrays vector


【解决方案1】:

我过于迂腐的评论太大了,所以我会试着把它变成一个有点迂回的答案。简短的回答可能只是坚持使用vector,但请确保使用reserve;哦,还有基准测试。

您没有说您使用的是什么编译器或 C++ 版本,所以我将使用我当前的 gcc.godbolt.org 默认 gcc 4.9.2、C++14。我还假设您确实希望将其作为一维数组,而不是更自然的(对于您的示例)3。

如果你在编译时知道N,你可以这样做(假设我得到了正确的数组偏移计算):

#include <array>
...
std::array<xyz, N*N*N> xyzs;
for (int i = 0; i < N; i++) {
  for (int j = 0; j < N; j++) {
    for (int k = 0; k < N; k++) {
      xyzs[i*N*N+j*N+k] = {i, j, k};
    }
  }
}

最大的缺点,IMO:

  • 容易出错的偏移量计算
  • 取决于N,代码运行的位置等,这可能会炸毁堆栈

在我尝试过的编译器上,优化器似乎理解我们正在以连续顺序在数组中移动,并且生成的机器代码更合理,但如果您愿意,也可以这样编写:

#include <array>
...
std::array<xyz, N*N*N> xyzs;
auto p = xyzs.data();
for (int i = 0; i < N; ++i) {
  for (int j = 0; j < N; ++j) {
    for (int k = 0; k < N; ++k) {
      (*p++) = {i, j, k};
    }
  }
}

当然,如果您实际上在编译时知道 N,并且它不会破坏堆栈,您可以考虑使用 3 维数组 xyz xyzs[N][N][N];,因为这对于这些事情的方式可能更自然最终被使用。

正如 cmets 中所指出的,可变长度数组在 C++ 中是不合法的,但在 C99 中是合法的;如果你在编译时不知道N,你应该在堆外分配。

vector 和数组最终在内存布局方面是相同的;它们的不同之处在于vector 从堆中分配内存,而数组(正如您正在编写的那样)将在堆栈上。我唯一的建议是在进入循环之前致电reserve

vect.reserve(N*N*N);

这意味着您只需要预先分配一个内存,而不是从默认构造的vector 获得的增长和复制机制。

假设xyz 和你在这里声明的一样简单,你也可以像上面第二个例子那样做:

std::vector<xyz> xyzs{N*N*N};
auto p = xyzs.data();
for (int i = 0; i < N; ++i) {
  for (int j = 0; j < N; ++j) {
    for (int k = 0; k < N; ++k) {
      (*p++) = {i, j, k};
    }
  }
}

您将失去push_back 的安全性,并且如果xyz 默认构造函数需要执行任何操作(例如,如果xyz 成员更改为具有默认值),则效率会降低。

说了这么多,您确实应该进行基准测试。但是,您可能应该对最终使用该数组的代码进行基准测试,而不是构建它的代码;如果建筑占主导地位,我还有其他顾虑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多