在析构函数中释放内存时出现segfault

Seg fault when deallocating memory in destructor

本文关键字:segfault 内存 析构函数 释放      更新时间:2023-10-16

有两个简单的类。当我在类(empty ~A(){};)中有一个析构函数时,一切都很好。当我添加两行来释放一个数组时,我的程序给了我分段错误。

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
class A
{
    private :
        int n;
        int m;
        int **array;
    public :
        A();
        A(int nn, int mm);
        A(const A& a);
        A& operator=(A a);
        int getAt(int i, int j);
        int getN(){return n;}
        int getM(){return m;}
        ~A();
};
A::A()
{
    n = 0;
    m = 0;
    array = NULL;
}
A::A(int nn, int mm)
{
    n = nn;
    m = mm;
    array = new int*[n];
    for(int i = 0; i <n; i++)
        array[i] = new int[m];
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            array[i][j] = rand()%2;
}
A::A(const A& a)
{
    for(int i=0; i <n; i++)
        delete[] array[i];
    delete [] array;
    array = NULL;
    n = a.n;
    m = a.m;
    array = new int*[n];
    for(int i = 0; i <n; i++)
        array[i] = new int[m];
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            array[i][j] = a.array[i][j];
}
A& A::operator=(A a)
{
    for(int i=0; i <n; i++)
        delete[] array[i];
    delete [] array;
    array = NULL;
    n = a.n;
    m = a.m;
    array = new int*[n];
    for(int i = 0; i <n; i++)
        array[i] = new int[m];
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            array[i][j] = a.array[i][j];
    return *this;
}
int A::getAt(int i, int j)
{
    return array[i][j];
}
A::~A()
{
    for(int i=0; i <n; i++)
        delete[] array[i];
    delete [] array;
    array = NULL;
}
class B
{
    private :
            A a;
    public :
            B(){}
            B(A aa);
            void setA(A aa);
            void showA();
};
B::B(A aa)
{
    a = aa;
}
void B::setA(A aa)
{
    a = aa;
}
void B::showA()
{
    int n = a.getN();
    int m = a.getM();
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++)
            cout << a.getAt(i,j) << " ";
        cout << "n";
    }
    cout << "n";
}
int main()
{
    A a(3, 4);
    B b(a);
    b.showA();
    return 0;
}

如何解决这个问题?为什么会发生这种情况?

解决:

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
class A
{
    private :
        int n;
        int m;
        int **array;
    public :
        A();
        A(int nn, int mm);
        A(const A& a);
        A& operator=(const A& a);
        int getAt(int i, int j);
        int getN(){return n;}
        int getM(){return m;}
        ~A();
};
A::A()
{
    n = 0;
    m = 0;
    array = NULL;
}
A::A(int nn, int mm)
{
    n = nn;
    m = mm;
    array = new int*[n];
    for(int i = 0; i <n; i++)
        array[i] = new int[m];
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            array[i][j] = rand()%2;
}
A::A(const A& a)
{
    n = a.n;
    m = a.m;
    array = new int*[n];
    for(int i = 0; i <n; i++)
        array[i] = new int[m];
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            array[i][j] = a.array[i][j];
}
A& A::operator=(const A& a)
{
    for(int i=0; i <n; i++)
        delete[] array[i];
    delete [] array;
    array = NULL;
    n = a.n;
    m = a.m;
    array = new int*[n];
    for(int i = 0; i <n; i++)
        array[i] = new int[m];
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            array[i][j] = a.array[i][j];
    return *this;
}
int A::getAt(int i, int j)
{
    return array[i][j];
}
A::~A()
{
    for(int i=0; i <n; i++)
        delete[] array[i];
    delete [] array;
    array = NULL;
}
class B
{
    private :
            A a;
    public :
            B(){}
            B(A aa);
            void setA(A aa);
            void showA();
};
B::B(A aa)
{
    a = aa;
}
void B::setA(A aa)
{
    a = aa;
}
void B::showA()
{
    int n = a.getN();
    int m = a.getM();
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++)
            cout << a.getAt(i,j) << " ";
        cout << "n";
    }
    cout << "n";
}
int main()
{
    A a(3, 4);
    B b(a);
    b.showA();
    return 0;
}

您的复制构造函数首先用新的n覆盖旧的n,然后尝试删除旧数组的n元素。但是如果数组的大小不同呢?覆盖循环后的n

或者,更好的是,摆脱这个可怕的指针怪物,使用std::vector代替。

首先,您违反了"三原则"(在任何分配内存的类中,都需要有一个复制构造函数和赋值操作符,以适当的方式"处理"分配的内存)。

你的析构函数在"数组"为NULL的情况下也会失效——你需要在运行循环删除内部部分之前检查数组是否为NULL。