在函数中分配内存并返回

时间:2018-12-05 08:37:22

标签: c++ memory-management

int** transpose(int** matrix,int row, int column)
{
    int** new_mat = new int*[column];


    for(int i = 0; i < column; i++)
    {
        new_mat[i] = new int[row];
    }
    for(int i  = 0; i < row; i++ )
    {
        for(int j = 0; j < column; j ++)
        {
            new_mat[j][i] = matrix[i][j];
        }
    }

    return new_mat;
}

我已经编写了此函数,但是感觉有些错误,我无法决定是否应该以某种方式删除new_mat,基本上函数会返回此值,我应该如何在不使用任何智能指针的情况下使用内存进行管理?

5 个答案:

答案 0 :(得分:1)

调用方将使用返回的矩阵。

此外,它可以获得所有权。结果,当不再需要矩阵时,可以将其删除。

为您提供的另一个选项是提供另一个功能,该功能将删除矩阵。然后,调用者必须调用该函数以取消动态分配的内存。


但是,智能指针是C ++的一项不错的功能,我鼓励您尝试一下。

此外,由于使用此C ++,因此可以将std::vector<std::vector<int>>用作矩阵的类型。这样,您不必担心内存管理,因为有关它的所有事情都会自动发生。

答案 1 :(得分:1)

如果您不想使用任何智能指针和向量,请尝试这样。 matrix -是尺寸为[col] [row]的2D动态数组的包装。

#include <iostream>
#include <algorithm>

using namespace std;

class matrix
{
private:
    unsigned int m_row;
    unsigned int m_col;
    int **m_data;

public:    
    matrix(unsigned int row, unsigned int col) : m_row(row), m_col(col), m_data(nullptr)
    {
        alloc();
    }

    matrix(const matrix &m) : m_row(m.get_rows_count()), m_col(m.get_cols_count()), m_data(nullptr)
    {
        alloc();
        for(unsigned int i = 0; i < m_row; i++)
            for(unsigned int j = 0; j < m_col; j++)
                m_data[i][j] = m[i][j];
    }

    ~matrix()
    {
        free();
    }

    unsigned int get_rows_count() const { return m_row; }
    unsigned int get_cols_count() const { return m_col; }
    const int* operator[](unsigned int ind) const
    {
        return m_data[ind];
    }
    int* operator[](unsigned int ind)
    {
        return m_data[ind];
    }

    matrix& operator=(const matrix &m)
    {
        free();
        m_row = m.get_rows_count();
        m_col = m.get_cols_count();
        alloc();
        for(unsigned int i = 0; i < m_row; i++)
            for(unsigned int j = 0; j < m_col; j++)
                m_data[i][j] = m[i][j];
        return *this;
    }

// you need move-operations:
    //matrix(matrix&& other) = delete;       // move constructor (rule of 5)
    //matrix& operator=(matrix&& other);     // move assignment  (rule of 5)

    void print()
    {
        for(unsigned int i = 0; i < m_row; i++)
        {
            for(unsigned int j = 0; j < m_col; j++)
                cout << m_data[i][j] << " ";
            cout << endl;
        }
    }

private:
    void alloc()
    {
        if(m_data)
            return;
        m_data = new int*[m_row];
        for(unsigned int i = 0; i < m_row; i++)
        {
            m_data[i] = new int[m_col];
            std::fill(m_data[i], m_data[i] + m_col, 0);
        }
    }
    void free()
    {
        if(!m_data)
            return;
        for(unsigned int i = 0; i < m_row; i++)
            delete[]m_data[i];
        delete[]m_data;
        m_data = nullptr;
    }
};

matrix transpose(const matrix matrix_in)
{
    unsigned int M = matrix_in.get_rows_count();
    unsigned int N = matrix_in.get_cols_count();
    matrix out(N, M);

    for(unsigned int i = 0; i < M; i++)
        for(unsigned int j = 0; j < N; j++)
            out[j][i] = matrix_in[i][j];
    return out;
}


int main(int argc, char* argv[])
{
    matrix m1(5, 7);
    m1[0][1] = m1[0][2] = m1[0][3] = 7;
    auto m2 = transpose(m1);
    m1.print();
    cout << endl;
    m2.print();
}

无论如何,最好在分配内存的同一位置释放内存。如果您不想使用某些类,可以这样做:

void transpose(int **matr_in, int **matr_out, int M, int N)
{
    for(int i = 0; i < M; i++)
        for(int j = 0; j < N; j++)
            matr_out[j][i] = matr_in[i][j];
}

int **create_matrix(int M, int N)
{
    int **m = new int*[M];
    for(int i = 0; i < M; i++)
        m[i] = new int[N];
    return m;
}

void delete_matrix(int **m, int M)
{
    for(int i = 0; i < M; i++)
        delete []m[i];
    delete []m;
}


int main()
{
    int M = 5, N = 4;
    int **m1 = create_matrix(M, N);
// fill matrix m1
    int **m2 = create_matrix(N, M);

    transpose(m1, m2, M, N);

    delete_matrix(m1, M);
    delete_matrix(m2, N);

    return 0;
}

答案 2 :(得分:1)

要回答所问的问题,调用者将需要释放返回的指针。对于函数中运算符new的每次使用,在调用者中都需要有运算符delete的相应用法。当不再需要返回的矩阵时,即随后不应该使用delete d的任何东西,调用方将执行此操作。

一个更好的方法-在许多方面(包括没有可能忘记释放内存的可能性)-避免直接使用指针,避免直接使用运算符new(或变体)或运算符delete。而是使用标准容器,例如std::vector(std::vector<int> >。如果使用得当,标准容器将管理它们自己的元素,并保留其自身大小的记录,因此就不会发生内存泄漏(当标准容器不再存在时,它使用的任何动态分配的内存也会被释放)。

原则上,您应该能够将函数简化为声明为

的内容
 std::vector<std::vector<int> > transpose(const std::vector<std::vector<int> > &matrix);

而不是需要将行和列的数目作为单独的参数传递(向量将保持跟踪)。我将把实现该功能作为练习,因为您将通过这种方式了解更多使用方法。

答案 3 :(得分:1)

您真的应该考虑一下矩阵表示形式:

int** matrix = ...; // create matrix of 10x12

// doing quite a lot of stuff

delete[] matrix[7]; // possibly even forgotten -> memory leak
matrix[7] = new int[7];

,您现在有了一个锯齿状的数组。尽管std::vector可以使您摆脱所有内存管理的麻烦,但是您仍然无法通过以下方式防止锯齿状的阵列:

std::vector<std::vector<int>> matrix = ...; // create matrix of 10x12

// doing quite a lot of stuff

matrix[7].resize(7);

最安全的方法是创建自己的围绕数据包装的类;我将使用std::vector来保存数据,这将使整个内存管理工作变得更加容易:

template <typename T> // more flexibility: you can use arbitrary data types...
class Matrix          // (but you don't _need_ to make a template from)
{
    std::vector<std::vector<T>> data;
public:
    Matrix(size_t rows, size_t columns)
        : data(rows)
    {
        for(auto& d : data)
            d.resize(columns);
    }
    // the nice thing about using std::vector as data container is
    // that default generated move/copy constructors/assignment
    // operators and destructor are fine already, so you can forget
    // about rule of three or five respectively

    // but you need ways to access your data:
    size_t rows() { return data.size(); }
    size_t columns() { return data.empty() ? 0 : data[0].size(); } 

    ??? operator[](size_t index);
    ??? operator[](size_t index) const;
 };

好吧,索引运算符...您真正想要实现的是可以像访问数组一样访问矩阵的东西:

Matrix<int> m(10, 12);
m[7][7] = 7;

但是我们应该返回什么?对内部向量的引用将再次允许修改其大小并以此方式创建锯齿状数组。解决方案:一个包装器类!

template <typename T>
class Matrix
{
    // all we had so far...

    template <typename Data>
    class Row
    {
        Data& data;
        friend class Matrix;

        Row(std::vector<T>& data)
                : data(data)
        { }
    public:
        // default constructed constructors/operators/destructor
        // themselves and being public are fine again...
        auto& operator[](size_t index) { return data[index]; }
    };
    auto operator[](size_t index) { return Row(data[index]); }
    auto operator[](size_t index) const { return Row(data[index]); }
};

为什么Row是模板?好吧,我们需要不同的Row类型(对数据的可变和不可变访问)作为两个不同索引运算符的返回类型...

最后:如果您实现自己,我将对私有/公共部分进行重新排序,以使公共优先。这提高了Matrix类的用户的可读性,因为他们只对公共接口感兴趣(通常),除非他们打算从公共接口进行继承。但这(当前)在这里无论如何都不是一个好主意,因为此类并非针对此类,就像std::vector也不是。如果需要:将析构函数设为虚拟:

virtual ~Matrix() = default;

如果您觉得比较自在,则可以 明确规定三五规则:

Matrix(Matrix const& other) = default;            // rule of three
Matrix& operator=(Matrix const& other) = default; // rule of three
Matrix(Matrix&& other) = default;                 // rule of five
Matrix& operator=(Matrix&& other) = default;      // rule of five

类似于Row类。请注意,如果您坚持在内部使用原始数组,那么您将必须明确地编写所有这些文件!

然后可以通过一个自由函数再次进行转置矩阵:

Matrix transpose(Matrix const& m)
{
    Matrix t(m.columns(), m.rows());
    // loops as you had
    return t;
}

您甚至可以提供一个可以对矩阵本身进行转置的成员函数,最好:使用上面的转置函数:

template <typename T>
class Matrix
{
public:
    void transpose()
    {
        Matrix t(transpose(*this));
        t.data.swap(data); // cleanup of previously owned data done in t's destructor...
    }

答案 4 :(得分:0)

您提供了一个函数,该函数返回一个指针数组,该数组保存单独的内存块(每个内存块代表一行)。那么您还必须在同一模块中同时提供free(或delete)功能(以确保内存管理功能完全匹配)。

int** transpose(int** matrix, int row, int column)
{
    int** new_mat = new int*[column];
    ...
    return new_mat;
}

//when free the mat, cols is not concerned; 
void free_mat(int** matrix, int rows)
{
     int i;

     for(i= 0; i< rows; i++)
         delete[] matrix[i];

     delete[] matrix;
}

//use the function as:
int** m2 = transpose(m1, rows, cols);
...
free_mat(m2, cols);

//after free_mat(), m2 still holds the address.
//so make it nullptr.

m2 = NULL; 

您还可以分配一个平面连续存储块以表示2维矩阵:

int* mat = new int[rows * cols];
//transfer mat[iRow][iCol] to mat[iRow * cols + iCol];
return mat;