10

我需要创建一个大小为 800x800 的 2D int 数组。但是这样做会造成堆栈溢出(哈哈)。

我是 C++ 新手,所以我应该做类似向量向量的事情吗?只是将二维数组封装到一个类中?

具体来说,这个数组是我在图形程序中的 zbuffer。我需要为屏幕上的每个像素存储 az 值(因此是 800x800 的大尺寸)。

谢谢!

4

10 回答 10

12

你需要大约 2.5 兆,所以只使用堆就可以了。除非您需要调整它的大小,否则您不需要矢量。有关使用“2D”堆数组的示例,请参阅C++ FAQ Lite 。

int *array = new int[800*800];

(完成后不要忘记delete[]它。)

于 2008-09-14T22:13:48.443 回答
10

到目前为止,每篇文章都将内存管理留给程序员。这可以而且应该避免。ReaperUnreal 与我所做的非常接近,除了我会使用向量而不是数组,还会制作维度模板参数并更改访问函数——哦,只是 IMNSHO 清理一下:

template <class T, size_t W, size_t H>
class Array2D
{
public:
    const int width = W;
    const int height = H;
    typedef typename T type;

    Array2D()
        : buffer(width*height)
    {
    }

    inline type& at(unsigned int x, unsigned int y)
    {
        return buffer[y*width + x];
    }

    inline const type& at(unsigned int x, unsigned int y) const
    {
        return buffer[y*width + x];
    }

private:
    std::vector<T> buffer;
};

现在您可以在堆栈上分配这个二维数组了:

void foo()
{
    Array2D<int, 800, 800> zbuffer;

    // Do something with zbuffer...
}

我希望这有帮助!

编辑:从Array2D::buffer. 感谢安德烈亚斯抓住了这一点!

于 2008-09-15T06:32:49.103 回答
4

然而,凯文的例子很好:

std::vector<T> buffer[width * height];

应该

std::vector<T> buffer;

稍微扩展一下,您当然可以添加运算符重载而不是 at() 函数:

const T &operator()(int x, int y) const
{
  return buffer[y * width + x];
}

T &operator()(int x, int y)
{
  return buffer[y * width + x];
}

例子:

int main()
{
  Array2D<int, 800, 800> a;
  a(10, 10) = 50;
  std::cout << "A(10, 10)=" << a(10, 10) << std::endl;
  return 0;
}
于 2008-09-15T07:08:30.437 回答
3

你可以做一个向量的向量,但这会产生一些开销。对于 z 缓冲区,更典型的方法是创建一个大小为 800*800=640000 的数组。

const int width = 800;
const int height = 800;
unsigned int* z_buffer = new unsigned int[width*height];

然后按如下方式访问像素:

unsigned int z = z_buffer[y*width+x];
于 2008-09-14T22:14:57.940 回答
2

我可能会创建一个 800*800 的单维数组。使用这样的单个分配可能更有效,而不是分配 800 个单独的向量。

int *ary=new int[800*800];

然后,可能将其封装在一个类似于二维数组的类中。

class _2DArray
{
  public:
  int *operator[](const size_t &idx)
  {
    return &ary[idx*800];
  }
  const int *operator[](const size_t &idx) const
  {
    return &ary[idx*800];
  }
};

这里显示的抽象有很多漏洞,例如,如果您访问超出“行”的末尾会发生什么?《Effective C++》一书对用 C++ 编写好的多维数组进行了很好的讨论。

于 2008-09-14T22:17:58.417 回答
1

有类似 C 的做法:

const int xwidth = 800;
const int ywidth = 800;
int* array = (int*) new int[xwidth * ywidth];
// Check array is not NULL here and handle the allocation error if it is
// Then do stuff with the array, such as zero initialize it
for(int x = 0; x < xwidth; ++x)
{
    for(int y = 0; y < ywidth; ++y)
    {
         array[y * xwidth + x] = 0;
    }
}
// Just use array[y * xwidth + x] when you want to access your class.

// When you're done with it, free the memory you allocated with
delete[] array;

您可以使用简单的 get 和 set 方法封装y * xwidth + x类内部([]如果您想开始使用更高级的 C++,可能会重载运算符)。如果你刚开始使用 C++ 并且没有开始为 n 维数组创建可重用的完全类模板,我建议你慢慢来,这只会让你在开始时感到困惑。

一旦您开始从事图形工作,您可能会发现额外调用类的开销可能会减慢您的代码速度。但是,在您的应用程序不够快之前不要担心这一点,并且您可以对其进行分析以显示时间损失的地方,而不是在一开始就使其更难使用,并可能带来不必要的复杂性。

我发现 C++ lite FAQ 非常适合此类信息。特别是您的问题由以下人员回答:

http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.16

于 2008-09-14T22:21:46.507 回答
1

您可以做的一件事是使用 VC 更改堆栈大小(如果您真的想要堆栈上的数组),这样做的标志是 [ /F](http://msdn.microsoft.com/en-us/library/ tdkhxaks(VS.80).aspx)

但是您可能想要的解决方案是将内存放在堆中而不是堆栈中,因为您应该使用 a vectorof vectors.

以下行声明了 a vectorof 800 个元素,每个元素是 a vectorof 800 ints,并且使您免于手动管理内存。

std::vector<std::vector<int> > arr(800, std::vector<int>(800));

注意两个右尖括号 ( ) 之间的空格,这是为了消除右移运算符的歧义(在C++0x> >中不再需要)。

于 2008-09-15T06:53:40.317 回答
1

或者您可以尝试以下方法:

boost::shared_array<int> zbuffer(new int[width*height]);

您仍然应该可以这样做:

++zbuffer[0];

无需再担心管理内存,无需处理自定义类,而且很容易扔掉。

于 2008-09-15T07:37:57.730 回答
1

如果您只需要一个实例,您可以在静态存储上分配数组(在文件范围内,或static在函数范围内添加限定符)。

int array[800][800];

void fn()
{
    static int array[800][800];
}

这样它就不会进入堆栈,并且您不必处理动态内存。

于 2008-09-15T13:01:38.747 回答
-1

好吧,在 Niall Ryan 开始的基础上,如果性能是一个问题,您可以通过优化数学并将其封装到一个类中来更进一步。

所以我们将从一些数学开始。回想一下,800 可以用 2 的幂写为:

800 = 512 + 256 + 32 = 2^5 + 2^8 + 2^9

所以我们可以把寻址函数写成:

int index = y << 9 + y << 8 + y << 5 + x;

因此,如果我们将所有内容封装到一个不错的类中,我们会得到:

class ZBuffer
{
public:
    const int width = 800;
    const int height = 800;

    ZBuffer()
    {
        for(unsigned int i = 0, *pBuff = zbuff; i < width * height; i++, pBuff++)
            *pBuff = 0;
    }

    inline unsigned int getZAt(unsigned int x, unsigned int y)
    {
        return *(zbuff + y << 9 + y << 8 + y << 5 + x);
    }

    inline unsigned int setZAt(unsigned int x, unsigned int y, unsigned int z)
    {
        *(zbuff + y << 9 + y << 8 + y << 5 + x) = z;
    }
private:
    unsigned int zbuff[width * height];
};
于 2008-09-14T22:29:03.430 回答