0

既に宣言さMatrixれているものを別のものに割り当てると、プログラムが予期せず終了します。

なぜこれが起こるのか本当にわかりません.代入演算子をコンパイラに生成させておくのが最善の方法であるという印象を受けました.絶対にオーバーロードする必要がない限り. ?

例:

Matrix rotation = rotationMatrix3(Y, degToRad(20.0f));
Vector3 left = rotation * direction_;

rotation = rotationMatrix3(Y, degToRad(-20.0f)); //crash
Vector3 right = rotation * direction_;

ここに私のマトリックスクラスがあります:

Matrix.h

enum Axis {
    X, Y, Z,
};

class Matrix {
public:
    Matrix(int cols, int rows);
    Matrix(int cols, int rows, const float values[]);
    ~Matrix();

    float& operator()(int col, int row);
    float  operator()(int col, int row) const;
    inline int cols() const { return cols_; }
    inline int rows() const { return rows_; }

private:
    int cols_, rows_;
    float* values_;
};

Vector3 operator*(const Matrix& m, const Vector3& v);

Matrix rotationMatrix3(int axis, float rads);

マトリックス.cpp

Matrix::Matrix(int cols, int rows) : cols_(cols), rows_(rows), values_(NULL) {
    values_ = new float[rows_ * cols_];
}

Matrix::Matrix(int cols, int rows, const float values[]) : cols_(cols), rows_(rows), values_(NULL) {
    values_ = new float[rows_ * cols_];

    for(int c = 0; c < cols; ++c) {
        for(int r = 0; r < rows; ++r) {
            (*this)(c, r) = values[r * cols + c];
        }
    }
}

Matrix::~Matrix() {
    delete [] values_;
}

float& Matrix::operator()(int col, int row) {
    return values_[row * cols_ + col];
}

float Matrix::operator()(int col, int row) const {
    return values_[row * cols_ + col];
}

Vector3 operator*(const Matrix& m, const Vector3& v) {
    if(m.cols() != 3) {
        throw std::logic_error("Matrix must have only 3 cols");
    }

    Vector3 result;
    result.x = m(0, 0) * v.x + m(1, 0) * v.y + m(2, 0) * v.z;
    result.y = m(0, 1) * v.x + m(1, 1) * v.y + m(2, 1) * v.z;
    result.z = m(0, 2) * v.x + m(1, 2) * v.y + m(2, 2) * v.z;

    return result;
}

Matrix rotationMatrix3(int axis, float rads) {
    float c = static_cast<float>(cos(rads));
    float s = static_cast<float>(sin(rads));

    if(axis == X) {
        const float mat[] = { 1.0f, 0.0f, 0.0f,
                              0.0f, c,    -s,
                              0.0f, s,    c };
        return Matrix(3, 3, mat);
    } else if(axis == Y) {
        const float mat[] = { c,    0.0f, s,
                              0.0f, 1.0f, 0.0f,
                              -s,   0.0f, c };
        return Matrix(3, 3, mat);
    } else if(axis == Z) {
        const float mat[] = { c,    -s,   0.0f,
                              s,    c,    0.0f,
                              0.0f, 0.0f, 1.0f };
        return Matrix(3, 3, mat);
    } else {
        throw std::logic_error("Unknown axis");
    }
}
4

2 に答える 2

2

はい、行列を取るコピー コンストラクタを作成します。values_それ以外の場合は、スコープからすぐに削除される元の戻り値で後で削除されるポインターをコピーします。

あなたへの私のアドバイス...あなたは明らかに3Dを行うためのクラスを作成しています。このために、任意のサイズの行列クラスを作成しないでください。基本的な 4x4 同種行列 (必要に応じて 4x3 または 3x3) を作成するだけです。ハードコーディング。値の単一配列 - 動的割り当てなし。多くの時間を節約し、ヒープの断片化と煩わしいサニティ テストを行います。このクラスを 5x17 マトリックスなどで実行することは決してありません。したがって、それをコーディングしないでください。

通常、2 次元、3 次元、または 4 次元のベクトルと、3 次元または 4 次元の正方行列が必要です。それで全部です。だからあなたのクラスを作ります:

Vector2
Vector3
Vector4
Matrix3
Matrix4
于 2012-07-30T23:30:44.290 に答える
2

コンパイラーが代入演算子を生成するようにしておくことが、絶対にオーバーロードする必要がない限り、最善の方法であるという印象を受けました。これにより、コンストラクターまたは何かに問題があると思いますか?

その印象を落とします。言語からのこれらの景品は、めったに「正しい」ことではありません。クラスに生のポインターfloat* values_;があります。ここでは、コピー コンストラクターと代入演算子をオーバーロードする必要があります。

于 2012-07-30T23:34:20.423 に答える