如何在C++中動態(tài)分配二維數(shù)組

字號:

這個問題應(yīng)該是我以前在CSDN蹭分時回答次數(shù)比較多的一個問題了,我的回答一般是三種方法:(1)用vector的vector,(2)先分配一個指針 數(shù)組,然后讓里面每一個指針再指向一個數(shù)組,這個做法的好處是訪問數(shù)組元素時比較直觀,可以用a[x][y]這樣的寫法,缺點是它相當(dāng)于C#中的一個鋸齒 數(shù)組,內(nèi)存空間不連續(xù)。(3)直接分配一個x*y大小的一維數(shù)組,這樣保證空間是連續(xù)的,但訪問數(shù)組元素不直觀。對于我這個“經(jīng)典”回答,我那時還一直是 挺得意的,至少從蹭分的角度來看,這樣回答還是很有效的。
    今天在ChinaUnix論壇閑逛時看到一個貼子,再次證明了我在C++方面才疏學(xué)淺。
    #include
    #include
    #include
    void **darray_new(int row, int col, int size)
    {
    void **arr;
    arr = (void **) malloc(sizeof(void *) * row + size * row * col); if (arr != NULL)
       {
      void *head;
      head = (void *) arr + sizeof(void *) * row;        memset(arr, 0, sizeof(void *) * row + size * row * col);    while (row--)
           arr[row] = head + size * row * col;
    }
      return arr;
    }
    void darray_free(void **arr)
    {
    if (arr != NULL)
     free(arr);
    }
    嗯,連續(xù)分配內(nèi)存,而且可以用a[x][y]的方式來訪問!可謂二維數(shù)組動態(tài)分配的絕妙方法!這段程序是C的,似乎要改成支持對象分配的C++版也不是什么難事(不過估計得用上placement new吧,嗯,需要再思考一下……)。
    經(jīng)過試驗,C++版出爐了:)關(guān)鍵點還是在于placement new和顯示的析構(gòu)函數(shù)調(diào)用,用于保證對象可以正常的構(gòu)造和析構(gòu)。
    這個實現(xiàn)也還是有不少缺點的,比如,數(shù)組的大小必須記住,才能保證析構(gòu)所有對象。不過這點可以通過改進分配方法算法,把數(shù)組大小也用一點空間保存起來。
    另一個缺點是,從語法上看,很容易讓人誤把darray_new返回的指針以為是數(shù)據(jù)區(qū)的起始地址,從而可能導(dǎo)致一些邏輯錯誤。
    #include
    #include
    #include
    template
    T **darray_new(int row, int col)
    {
        int size = sizeof(T);
        void **arr = (void **) malloc(sizeof(void *) * row + size * row * col);
        if (arr != NULL)
        {
        unsigned char * head;
        head = (unsigned char *) arr + sizeof(void *) * row;
        for (int i = 0; i < row; ++i)
        {
        arr[i] = head + size * i * col;
        for (int j = 0; j < col; ++j)
        new (head + size * (i * col + j)) T;
        }
       }
       return (T**) arr;
    }
    template
    void darray_free(T **arr, int row, int col)
    {
        for (int i = 0; i < row; ++i)
        for (int j = 0; j < col; ++j)
       arr[i][j].~T();
       if (arr != NULL)
       free((void **)arr);
    }