0

サイズを動的に再割り当てする行列クラスがあります。具体的には、行の配列を動的に再割り当てします。

ただし、場合によっては、マトリックスのデストラクタが呼び出されたときにメモリ解放の問題が発生します。

***glibcが検出されました***./solver:free():invalid next size(fast):0x0000000000c112b0 ***

プロセスは中止されています。

Matrixクラス:

#ifndef __matrix_hpp
#define __matrix_hpp

#include <cstring>
#include <stdexcept>
#include "row.hpp"

using namespace std;

class Matrix {

public:
    Matrix();
    ~Matrix();
    size_t size();
    void resize(size_t size);
    double get(size_t x, size_t y) throw (out_of_range);
    void set(size_t x, size_t y, double value) throw (out_of_range);
    double getfv(size_t y) throw (out_of_range);
    void setfv(size_t y, double value) throw (out_of_range);
    void optimize(size_t y) throw (out_of_range);
    void _print();

private:
    size_t sz;
    Row **data;

};

#endif

そして重要な機能の本体:

Matrix::~Matrix() {
    if (data != NULL) {
        for (size_t i = 0; i < sz; ++i)
            delete data[i];
        delete [] data;
    }
}

void Matrix::resize(size_t size) {
    if (size == sz)
        return;
    Row **newData = new Row *[size];
    if (data != NULL)
        memcpy(newData, data, sz * sizeof(Row*));
    if (size > sz) {
        for (size_t i = sz; i < size; ++i)
            newData[i] = new Row();
    }
    else {
        for (size_t i = size; i < sz; ++i)
            delete data[i];
    }
    delete [] data;
    data = newData;
    sz = size;
}

これがコードです。問題は、行列を作成し、後でそのサイズを縮小してdesctructorを呼び出すときに発生します。例えば:

Matrix *matrix = new Matrix();
matrix->resize(10);
matrix->resize(7);
delete matrix;

しかし、マトリックスを大きくすると、かなりうまくいきます。

Matrix *matrix = new Matrix();
matrix->resize(10);
matrix->resize(13);
delete matrix;

そして、最もおかしなことに、この例は機能します。

Matrix *matrix = new Matrix();
matrix->resize(3);
matrix->resize(2);
delete matrix;

だから私は何が間違っているのか分かりません。助言がありますか?

4

3 に答える 3

2

エラーは、割り当てられたスペースの外に書き込むことです。原因はこの行です

Row **newData = new Row *[size];
if (data != NULL)
    memcpy(newData, data, sz * sizeof(Row*));

szがサイズよりも大きい場合は、書き込みが多すぎてヒープが破壊される可能性があります。以下のコードに変更すると、すべてがうまく機能するはずです。このようにして、常に有効なデータをコピーし、割り当てたデータを超えないようにします。

Row **newData = new Row *[size];
if (data != NULL)
    memcpy(newData, data, (size>sz?sz:size) * sizeof(Row*));

3から2の作品へのサイズ変更は、運(そしてヒープがどのように機能するか)にかかっています。

また、new Row []が失敗するかどうかはチェックしませんが、失敗するとNULLポインター例外が発生します。

于 2012-11-27T00:58:27.377 に答える
1

非常に大雑把な調査の後、問題はこれだと思います。

if (data != NULL)
    memcpy(newData, data, sz * sizeof(Row*));

たとえば10から7に縮小する場合は、サイズが7のバッファーに10個のポインターをコピーしただけです。

于 2012-11-27T00:52:29.373 に答える
0

これは、メモリを割り当て、そのメモリの終わりを超えて書き込み、空きヒープの管理に使用される所有していないメモリを上書きした場合に発生します。

割り当てられたメモリに書き込むすべての場所を確認します。要求して正当に所有しているメモリの終わりを超えて書き込みを行わないようにしてください。

于 2012-11-27T00:55:00.463 に答える