c++ 中的高维数组(1)
数值计算中,常常需要操作高维数组,C++ 很容易写出来占用内存多,而且速度慢的程序。
#include <iostream>
using namespace std;
class Video {
public:
Video(size_t num_of_channels, size_t width, size_t height,
size_t num_of_colors)
: num_of_channels_(num_of_channels),
width_(width),
height_(height),
num_of_colors_(num_of_colors) {
buf_ = new char***[num_of_channels];
for (size_t c = 0; c < num_of_channels; ++c) {
buf_[c] = new char**[width];
for (size_t w = 0; w < width; ++w) {
buf_[c][w] = new char*[height];
for (size_t h = 0; h < height; ++h) {
buf_[c][w][h] = new char[num_of_colors];
for (size_t r = 0; r < num_of_colors; ++r) {
buf_[c][w][h][r] = 0.0;
}
}
}
}
}
~Video() {
for (size_t c = 0; c < num_of_channels_; ++c) {
for (size_t w = 0; w < width_; ++w) {
for (size_t h = 0; h < height_; ++h) {
delete[] buf_[c][w][h];
}
delete[] buf_[c][w];
}
delete[] buf_[c];
}
delete[] buf_;
}
private:
const size_t num_of_channels_;
const size_t width_;
const size_t height_;
const size_t num_of_colors_;
char **** buf_;
};
int main(int argc, char *argv[])
{
Video v(10,1920,1080,3);
return 0;
}
我碰到过一些真实的,代码量很大的项目,至少三次看到上面这种模式。这种方法占用内存多,速度慢。
可以用一维数组模拟高维数组。
#include <iostream>
using namespace std;
class Video {
public:
Video(size_t num_of_channels, size_t width, size_t height,
size_t num_of_colors)
: num_of_channels_(num_of_channels),
width_(width),
height_(height),
num_of_colors_(num_of_colors) {
buf_ = new char[num_of_channels * width * height * num_of_colors];
for (size_t c = 0; c < num_of_channels; ++c) {
for (size_t w = 0; w < width; ++w) {
for (size_t h = 0; h < height; ++h) {
for (size_t r = 0; r < num_of_colors; ++r) {
buf_[c*width*height*num_of_colors + w*height*num_of_colors + h*num_of_colors + r] = 0.0;
}
}
}
}
}
~Video() {
delete[] buf_;
}
private:
const size_t num_of_channels_;
const size_t width_;
const size_t height_;
const size_t num_of_colors_;
char * buf_;
};
int main(int argc, char *argv[])
{
Video v(10,1920,1080,3);
return 0;
}
我们看看速度
% c++ -std=c++11 high_dim_array_1.cpp
% ./a.out
real 0m3.046s
user 0m2.801s
sys 0m0.235s
% c++ -std=c++11 high_dim_array_2.cpp
% ./a.out
real 0m0.244s
user 0m0.206s
sys 0m0.028s
后者快了 14 倍。
我们分析一下内存使用。对于数据来说,二者是一样的。但是第一种方案,额外存储了很多内存指针。
new char***[num_of_channels];
需要 10 个指针。- 同样道理,宽度层,需要 10 * 1920 个指针
- 高度层,需要 10*1920*1080 个指针
- 最后一层,没有额外的指针空间,因为这些就是原始数据了。
可以看到,每个指针 8 个字节(64位机器),我们额外需要大约 160M+ 的内存,存储间接指针。
buf_[c][w][h][r] = 0.0;
buf_[c*width*height*num_of_colors + w*height*num_of_colors + h*num_of_colors + r] = 0.0;
这两个相比,前者看起来更加干净。但是,我们很容易做做操作符重载
char& operator()(size_t c, size_t w, size_t h, size_t r){
return buf_[c*width*height*num_of_colors + w*height*num_of_colors + h*num_of_colors + r];
}
这样我们就可以使用下面的语法。
(*this)(c,w,h,r) = 0.0;
这里淡淡的吐槽一下 c++ ,(*this)[c,w,h,r] = 0.0;
也许更好,可惜 c++
的对方括号的操作符重载,只允许一个参数。
如果非要用第一种语法形式 (*this)[c][w][h][r]
的话,(*this)[c]
返回一个对象,依次产生三个临时对象。