0

解决了

解决方法:提供拷贝构造函数,遵循三者法则。

原来的问题

我正在实现一个作为间隔矩阵的类。我的 Intervall 类看起来像这样(缩短):

class Intervall
{
friend std::ostream& operator<<(std::ostream& output, const Intervall& i);

public:
    Intervall();
    Intervall(double n);

private:
    double min_value;
    double max_value;
};

有了这个实现:

Intervall::Intervall(){
    min_value = 0;
    max_value = 0;
}

Intervall::Intervall(double n){
    min_value = n;
    max_value = n;
}

ostream& operator<<(ostream& output, const Intervall& i){
    output << "[" <<  i.min_value << ", " << i.max_value <<"]";
    return output;
}

我的 Matrix 类如下所示:

class IntervallRMatrix
{
friend std::ostream& operator<<(std::ostream& output, const IntervallRMatrix& irm);

public:
   IntervallRMatrix();
   ~IntervallRMatrix();

   void setIdentity();

   IntervallRMatrix clone();

private:
   void initialize();

   Intervall* data;
   Intervall** cells;
};

通过以下实现:

IntervallRMatrix::IntervallRMatrix(){
    initialize();
}

IntervallRMatrix::~IntervallRMatrix(){
    delete cells;
    delete data;
}

ostream& operator<<(ostream& output, const IntervallRMatrix& irm){
    output << "3 x 3" << endl;
    for(int i=0; i<3; i++){
        for(int j=0; j<3; j++){
            output << irm.cells[i][j];
        }
        output << endl;
    }
    return output;
}

void IntervallRMatrix::setIdentity(){
    cells[0][0] = Intervall(1);
    cells[1][1] = Intervall(1);
    cells[2][2] = Intervall(1);
}

IntervallRMatrix IntervallRMatrix::clone(){
    IntervallRMatrix result;
    for(int i=0; i<3; i++){
        for(int j=0; j<3; j++){
            result.cells[i][j] = cells[i][j];
        }
    }
    return result;
}

void IntervallRMatrix::initialize(){
    data = new Intervall[9];
    for(int i=0; i<9; i++){
        data[i] = Intervall();
    }
    cells = new Intervall*[3];
    for(int i=0; i<3; i++){
        cells[i] = &data[3*i];
    }
}

在我使用克隆功能之前,这一切都很好。此代码产生内存错误:

int main()
{
    IntervallRMatrix m1;
    m1.setIdentity();
    cout << "m1: " << m1 << endl;

    IntervallRMatrix m2 = m1.clone();
    cout << "m2: " << m2 << endl;
    return 0;
}

第一个 cout 按预期工作。第二个 cout 没有。当程序试图读取时,错误就来了m2.cells[0][0]

cells and data如果我不在析构函数中删除,则不会发生此错误。

我以我的方式声明单元格和数据,因为我想重载方括号,以便以后可以编写Intervall = Matrix[i][j]. 我还想重载算术运算符,以便我可以编写Matrix m3 = m2*m1. 事实上,我已经这样做了,这就是错误首先发生的地方。

现在,最后我的问题:如何实现一个函数,该函数返回一个不会导致内存错误的 IntervallRMatrix,同时仍然能够释放析构函数中分配的内存?

4

2 回答 2

2

最好的解决方案是避免手动内存管理。使用适当的容器(例如std::vector)或智能指针。

如果您必须进行手动管理,请确保遵循“三法则”

于 2013-01-31T15:50:06.397 回答
0

这里的问题是 clone 方法返回您刚刚在堆栈上创建并初始化的结果对象的副本。由于您没有实现任何复制构造函数(从我们所见),编译器提供了一个默认构造函数。这个默认实现基本上会将成员变量从一个实例复制到另一个实例(在这种情况下,是指向单元格和数据的指针)。内容根本不会重复。一旦你离开克隆函数范围,结果对象就会被删除(作为前析构函数代码),你最终会得到一个结果副本,其中单元格和数据指针仍然指向刚刚空闲的内存。这会导致未定义的行为(通常读作“它会崩溃”)

遵循 Oli Charlesworth 在他的回答中提出的三法则。

于 2013-01-31T15:59:37.990 回答