簡體   English   中英

如何在 C++ 中處理非常大的二維數組

[英]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 放在堆中而不是堆棧中,因為您應該使用vectorvectors

下面的行聲明了一個包含 800 個元素的vector ,每個元素是一個 800 個intvector ,並且使您免於手動管理 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM