将 C++ 中的动态分配数组的大小调整为较小的大小

Resize a Dynamically allocated array in C++ to a smaller size

我正在尝试创建一种方法来调整动态分配的数组的大小。我可以添加行和列,但是无法将其调整为小于原始大小。

template <class T>
class Matrix
{
public:

// Constructors / Destructors
Matrix();
Matrix(const int rows, const int cols);
Matrix(const Matrix<T>& orig);
~Matrix();

// Display
void print() const;

// Size modification
void addRow();
void addCol();
void resize(const int rows, const int cols);

// Element access
T getCell(const int r, const int c) const;

// Operator Access
T& operator()(const int r, const int c)             { return mData[r * mCols + c]; }
const T& operator()(const int r, const int c) const { return mData[r * mCols + c]; }



// Getters / Setters
int getRows() const;
int getCols() const;

private:
    T* mData;
    int mRows, mCols;
};
//1
template <class T>
Matrix<T>::Matrix(void){
    mRows=0;
    mCols=0;
    mData=NULL;
}

//2
template <class T>
Matrix<T>::Matrix(const int rows, const int cols){
    if(rows!=0&&cols!=0)
    {
        mRows=rows;
        mCols=cols;
        int size = rows*cols;
        mData = new T[size];
        for(int r=0;r<getRows();r++)
        {
            for(int c=0;c<getCols();c++)
            {
                mData[r * mCols + c]=0;
            }
        }
    }else
    {
        mData=NULL;
    }
}

//3
template <class T>
Matrix<T>::Matrix(const Matrix<T>& orig){
    if(orig.getRows()!=0&&orig.getCols()!=0)
    {
        T* temp = mData;
        mRows=orig.getRows();
        mCols=orig.getCols();
        int size = mRows*mCols;
        mData = new T[size];
        for(int r=0;r<getRows();r++)
        {
            for(int c=0;c<getCols();c++)
            {
                mData[r * mCols + c]=temp[r * mCols + c];
            }
        }
    }else
    {
        mData=NULL;
    }
}

//4
template <class T>
Matrix<T>::~Matrix()
{
    delete []mData;
    mData=NULL;
}

//5
template <class T>
void Matrix<T>::print() const{  //to print the mData in a Matrix form
    cout << endl;
    int r=0,c=0,w=10;
    for(r=0;r<getRows();r++){
        for(c=0;c<getCols();c++){
            cout << setw(w) << mData[r * mCols + c];
        }
        cout << endl;
    }
}

//6
template <class T>
void Matrix<T>::addRow(){
    T* temp = mData;
    mRows=getRows()+1;
    int size = mRows*mCols;
    mData = new T[size];
    for(int r=0;r<getRows();r++)
    {
        for(int c=0;c<getCols();c++)
        {
            if(r==getRows()-1)
            {
                mData[r * mCols + c]=0;
            }else
            {
                mData[r * mCols + c]=temp[r * mCols + c];
            }

        }
    }
}

//7
template <class T>
void Matrix<T>::addCol(){
    T* temp = mData;
    mCols=getCols()+1;
    int size = mRows*mCols;
    mData = new T[size];
    for(int r=0;r<getRows();r++)
    {
        for(int c=0;c<getCols()-1;c++)
        {
                mData[r * mCols + c]=temp[r * (mCols-1) + c];
        }
    }
    int c=getCols()-1;
    for(int r=0;r<getRows();r++)
    {
            mData[r * mCols + c]=0;
    }
}

//8
template <class T>
void Matrix<T>::resize(const int rows, const int cols){


    if(rows>=getRows())
    {
        while(rows!=getRows())
        {
            addRow();
        }
    }

    if(cols>=getCols())
    {
        while(cols!=getCols())
        {
            addCol();
        }
    }


    T* temp = mData;
    int tempCols = getCols();
    int size = rows*cols;
    if(rows<getRows() || cols <getCols())
    {
        delete []mData;
        mData=NULL;
        mData= new T[size];
        for(int r=0;r<getRows();r++)
        {
            for(int c=0;c<getCols();c++)
            {
                    if(r<rows&&c<cols)
                    {
                        mData[r * mCols + c]=temp[r * (cols) + c];
                    }else
                    {
                        mData[r * mCols + c]=NULL;
                    }

            }
        }
    }

}


//9
template <class T>
T Matrix<T>:: getCell(const int r, const int c) const
{
    T value;
    if(r<getRows()&&c<getCols()&&r>=0&&c>=0)
    {
        value = mData[r * mCols + c] ;
    }else
    {
        value = 0;
    }
    return(value);
}

//22
template <class T>
int Matrix<T>::getRows() const{
    return mRows;
}
//23
template <class T>
int Matrix<T>::getCols() const{
    return mCols;
}
#endif

我实现的所有其他功能都完美运行,我添加了植入以帮助测试。

目前,如果您有一个 3,4 的矩阵,并且您想要增加到 4,7,它会成功地做到这一点。但是,如果您尝试将 t运行cate 为 2,2,它仍将保持为 3,4,即使根据新的大小和 for 循环它应该更小。

所以我的问题是如果我有一个 (3,4) 矩阵 M1

1 2 3 4
6 7 8 2
3 2 1 1

如果我运行 m1.resize(2,7) 我想得到

1 2 3 4 0 0 0
6 7 8 2 0 0 0

但是目前我得到

3801280 3802496 2 3 4 0 0 
6       7       8 2 0 0 0
0       0       0 0 0 0 0
0       0       0 0 0 0 0

我执行调整大小有什么问题?

T* temp = mData;不执行深拷贝。当你之后 delete []mData; 指向的数据 temp 也消失了。之后取消引用 temp 会触发未定义的行为。这是非常不幸的,因为这意味着你有时可能会随机得到正确的结果,但大多数时候它会失败。段错误会更好。

这是一个简短的例子。我还放置了不执行深度复制的 double * temp = mData; 行。

#include <algorithm>
#include <iostream>

int main()
{
  double * mData = new double[5];
  std::fill_n(mData, 5, 1);

  double * temp = mData; // Wrong! No deep copy
  //double * temp = new double[5];
  //std::copy(mData, mData+5, temp);

  delete[] mData;
  mData = new double[10];
  std::fill_n(mData, 10, 0); // fill with zeros
  for (int i = 0; i < 5; ++i)
    mData[i] = temp[i];

  for(int i = 0; i < 10; ++i)
    std::cout << mData[i] << ' ';
  std::cout << '\n';

  delete[] temp;
  delete[] mData;
}

这个程序的输出可能很好也可能不好。毕竟行为是未定义的。最好在内存调试器中 运行 具有手动内存管理的程序(例如 Linux 上的 valgrind)来检测无效操作。如果我 运行 以上 valgrind 我得到(在一些通用消息中)

==9998== Invalid read of size 8
==9998==    at 0x400908: main (in /home/henri/a.out)
==9998==  Address 0x5abfc80 is 0 bytes inside a block of size 40 free'd
==9998==    at 0x4C2F74B: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9998==    by 0x4008C1: main (in /home/henri/a.out)
==9998==  Block was alloc'd at
==9998==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9998==    by 0x40087A: main (in /home/henri/a.out)
==9998== 
1 1 1 1 1 0 0 0 0 0 
==9998== Invalid free() / delete / delete[] / realloc()
==9998==    at 0x4C2F74B: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9998==    by 0x4009A9: main (in /home/henri/a.out)
==9998==  Address 0x5abfc80 is 0 bytes inside a block of size 40 free'd
==9998==    at 0x4C2F74B: operator delete[](void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9998==    by 0x4008C1: main (in /home/henri/a.out)
==9998==  Block was alloc'd at
==9998==    at 0x4C2E80F: operator new[](unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9998==    by 0x40087A: main (in /home/henri/a.out)