[英]How to work around a very large 2d array in C++
我需要創建一個大小為 800x800 的 2D int 數組。 但是這樣做會造成堆棧溢出(哈哈)。
我是 C++ 的新手,所以我應該做類似向量向量的事情嗎? 並且只是將二維數組封裝到 class 中?
具體來說,這個數組是我在圖形程序中的 zbuffer。 我需要為屏幕上的每個像素存儲 az 值(因此是 800x800 的大尺寸)。
謝謝!
你需要大約 2.5 兆,所以只使用堆就可以了。 除非您需要調整它的大小,否則您不需要矢量。 有關使用“2D”堆數組的示例,請參閱C++ FAQ Lite 。
int *array = new int[800*800];
(完成后不要忘記delete[]
。)
到目前為止,每個帖子都為程序員留下了 memory 管理。 這可以而且應該避免。 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
中刪除了數組規范。 感謝安德烈亞斯抓住了這一點!
然而,凱文的例子很好:
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;
}
你可以做一個向量的向量,但這會產生一些開銷。 對於 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];
我可能會創建一個 800*800 的單維數組。 使用這樣的單個分配可能更有效,而不是分配 800 個單獨的向量。
int *ary=new int[800*800];
然后,可能將其封裝在像二維數組一樣的 class 中。
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++ 中編寫良好的多維 arrays 進行了很好的討論。
有類似 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
封裝在 class 中(如果您想開始使用更高級的 C++,可能會重載[]
運算符)。 我建議你慢慢來,但如果你只是從 C++ 開始,而不是開始為 n 維 arrays 創建可重復使用的完全 class 模板,那只會讓你感到困惑。
一旦你開始從事圖形工作,你可能會發現額外的 class 調用的開銷可能會減慢你的代碼。 但是,在您的應用程序不夠快之前不要擔心這一點,並且您可以對其進行分析以顯示時間損失的地方,而不是在一開始就使其更難使用,並可能帶來不必要的復雜性。
我發現 C++ lite FAQ 非常適合此類信息。 特別是您的問題由以下人員回答:
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.16
您可以做的一件事是使用 VC 更改堆棧大小(如果您真的想要堆棧上的數組),這樣做的標志是 [/F]( http://msdn.microsoft.com/en-us/library/ tdkhxaks(VS.80).aspx) 。
但是您可能想要的解決方案是將 memory 放在堆中而不是堆棧中,因為您應該使用vector
的vectors
。
下面的行聲明了一個包含 800 個元素的vector
,每個元素是一個 800 個int
的vector
,並且使您免於手動管理 memory。
std::vector<std::vector<int> > arr(800, std::vector<int>(800));
請注意兩個右尖括號 ( > >
) 之間的空格,這是為了消除它與右移運算符的歧義(在C++0x中不再需要)。
或者您可以嘗試以下方法:
boost::shared_array<int> zbuffer(new int[width*height]);
您仍然應該可以這樣做:
++zbuffer[0];
無需再擔心管理 memory,無需處理自定義類,而且很容易扔掉。
You can allocate array on static storage (in file's scope, or add static
qualifier in function scope), if you need only one instance.
int array[800][800];
void fn()
{
static int array[800][800];
}
這樣它就不會 go 到堆棧,並且您不必處理動態 memory。
好吧,在 Niall Ryan 開始的基礎上,如果性能是一個問題,您可以通過優化數學並將其封裝到 class 中更進一步。
所以我們將從一些數學開始。 回想一下,800 可以用 2 的冪寫為:
800 = 512 + 256 + 32 = 2^5 + 2^8 + 2^9
所以我們可以把我們的地址 function 寫成:
int index = y << 9 + y << 8 + y << 5 + x;
因此,如果我們將所有內容封裝到一個漂亮的 class 中,我們會得到:
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];
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.