C++矩阵破坏导致断点和严重错误(解决方案在问题的最后)

C++ matrix destruction causes breakpoint and critical error (solution is at the end of the question)

所以我想创建一个 4x4 矩阵 class,将其数据存储为 float** m。 我这样初始化它:

Matrix4f::Matrix4f()
{
    this->m = new float*[4];

    for (int i = 0; i < 4; i++)
    {
        this->m[i] = new float[4];
        memset(this->m[i], 0, sizeof(float) * 4);
    }
}

之后,我有一个这样的析构函数:

Matrix4f::~Matrix4f()
{
    for (int i = 0; i < 4; i++)
    {
        delete[] m[i];
    }

    delete[] m;
}

但有时当我使用这个 class 时,这一行:

delete[] m[i];

导致断点,并抛出:Critical error detected c0000374 这是初始化和删除 4x4 矩阵的正确方法吗?

编辑:对于未来的读者:我的问题是我没有重写矩阵的复制构造函数和赋值运算符 (void operator=(const Matrix&)。这是一个问题,因为有可能复制是默默地进行的(就像说 Matrix4f mat = getTransformationMatrix();,然后这个矩阵在范围的末尾被删除,释放与转换矩阵相同的指针,因为复制的是指针,而不是内容。所以覆盖这两个像接受的答案中的功能一样,它将摆脱这样的问题。

如前所述,三者的规则可能是问题所在。您提供的代码在技术上是正确的,但是,如果您复制 Matrix4f,则必须重新实现复制构造函数和重载赋值构造函数:

#include <iostream>


class Matrix4f
{
public:
    Matrix4f()
        : m_data(new float*[4])
    {
        for (int i = 0; i < 4; i++)
            m_data[i] = new float[4]{ 0 };
    }
    Matrix4f(const Matrix4f& source)
    {
        m_data = new float*[4];
        for (int i = 0; i < 4; i++)
        {
            m_data[i] = new float[4]{ 0 };
            for (int j = 0; j < 4; j++)
            {
                m_data[i][j] = source.m_data[i][j];
            }
        }
    }
    Matrix4f& operator=(const Matrix4f& source)
    {
        if (this == &source) return *this;

        clear();
        m_data = new float*[4];
        for (int i = 0; i < 4; i++)
        {
            m_data[i] = new float[4]{ 0 };
            for (int j = 0; j < 4; j++)
            {
                m_data[i][j] = source.m_data[i][j];
            }
        }

        return *this;
    }
    ~Matrix4f()
    {
        clear();
    }
//private:
    float**m_data;

    void clear()
    {
        if (m_data != NULL)
        {
            for (int i = 0; i < 4; i++)
            {
                delete[] m_data[i];
            }
            delete[]m_data;
        }
    }

    void print()const
    {
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                std::cout << m_data[i][j] << "\t";
            }
            std::cout << "\n";
        }
    }
};



int main()
{
    Matrix4f m1;

    m1.m_data[0][0] = m1.m_data[1][1] = m1.m_data[2][2] = m1.m_data[3][3]  = 1;

    {
        Matrix4f m2(m1);
        Matrix4f m3 = m2;

        m2.print();
        m3.print();
    }

    m1.print();
}

但我建议你改用一维向量,它更快更安全。

正如评论中所指出的,当且仅当您正确地管理副本的情况时,您的代码才可以。

你有三个选择:

  1. 禁用复制
  2. 浅拷贝
  3. 深拷贝

让我们讨论这个选择:

  1. 您只需要声明复制构造函数和删除的复制赋值运算符。现在无法复制 class 的对象。这降低了矩阵的有用性-class.

  2. 这本身没有实际价值。因为您可以通过将类型 3 的对象包装到 std::shared_ptr.

  3. 中来实现此目的
  4. 在这种情况下不需要动态内存。即使有,您也想使用 std::vector 或其他东西来管理内存。 明智的解决方案是使用 float[4][4] 作为 m。 这会更健壮,因为您避免了内存管理。