私は自分自身にはほとんど説明できない奇妙な副作用を経験しました。おそらく私は何か非常に明白なものを見逃しているかもしれませんが、私は数時間前にバグを探しました。コードはかなりシンプルなので、私はいくつかの基本的な誤解があるはずです。ネストされた配列型の定数変数への副作用
それは2つの2D行列の積を計算するためのものだった(私はデバッグ出力をより理解するために、引数のセルに-1
を追加するset()
機能を変更しました。
template<class T, unsigned column_count, unsigned row_count>
class Matrix
{
private:
const static unsigned row_length = column_count;
const static unsigned column_length = row_count;
using matrix_type = std::array<std::array<T, row_length>, row_count>;
matrix_type matrix;
public:
using value_type = T;
Matrix(const matrix_type& matrix) : matrix(matrix) {}
Matrix() {}
friend std::ostream& operator<<(std::ostream& o, const Matrix& rhs)
{
for (unsigned i = 0; i < column_count; ++i) {
for (unsigned j = 0; j < row_count; ++j) {
o << rhs.matrix[i][j] << ' ';
}
o << '\n';
}
return o;
}
const auto& get_rows() const { return matrix; }
const auto get_columns() const
{
std::array<std::array<T, column_length>, column_count> columns;
for (unsigned i = 0; i < row_length; ++i) {
for (unsigned j = 0; j < column_length; ++j) {
columns[i][j] = matrix[j][i];
}
}
return columns;
}
void set(unsigned i, unsigned j, T v) { matrix[i][j] = -1; }
friend Matrix operator*(const Matrix& m1, const Matrix& m2)
{
auto columns = m1.get_columns();
auto rows = m2.get_rows();
Matrix m3;
std::cout << "before:"
<< "\n";
std::cout << m1 << "\n";
std::cout << m2 << "\n";
std::cout << m3 << "\n";
unsigned i{ 0 };
for (const auto& row : rows) {
i++;
unsigned j{ 0 };
for (const auto& column : columns) {
j++;
value_type v{ 0 };
for (unsigned k = 0; k < column.size(); ++k) {
v += row[k] * column[k];
}
m3.set(i, j, v);
}
}
std::cout << "after:"
<< "\n";
std::cout << m1 << "\n";
std::cout << m2 << "\n";
std::cout << m3 << "\n";
return m3;
}
};
として、このコードを考えてみましょうあなたは、ゲッター機能を参照してくださいいずれかのコピーまたは一定の基準を返すことができますoperator*
機能は、一定のパラメータを取り
私は今、そうのような二つの行列を構築する:。。
std::array<int, 3> c1{ { 1, 2, 3 } };
std::array<int, 3> c2{ { 4, 5, 6 } };
std::array<int, 3> c3{ { 7, 8, 9 } };
std::array<std::array<int, 3>, 3> m1{ { c1, c2, c3 } };
std::array<std::array<int, 3>, 3> m2 = m1;
Matrix<int, 3, 3> matrix1(m1);
Matrix<int, 3, 3> matrix2(m2);
は今、私はさまざまな方法でoperator*
を呼び出す:
matrix1* matrix2;
結果:
before:
1 2 3
4 5 6
7 8 9
1 2 3
4 5 6
7 8 9
0 0 0
0 0 0
0 0 183238709
after:
-1 -1 -1
4 5 6
7 8 9
1 2 3
4 5 6
7 8 9
0 0 0
0 -1 -1
-1 -1 -1
matrix2* matrix1;
結果:
before:
1 2 3
4 5 6
7 8 9
1 2 3
4 5 6
7 8 9
0 0 0
0 0 0
0 0 -1823473620
after:
1 2 3
4 5 6
7 8 9
-1 -1 -1
4 5 6
7 8 9
0 0 0
0 -1 -1
-1 -1 -1
matrix1* matrix1;
結果:あなたが見ることができるように、最初の引数として渡される行列は
before:
1 2 3
4 5 6
7 8 9
1 2 3
4 5 6
7 8 9
1385085408 32767 401515081
1 1385085440 32767
1385085440 32767 1385085464
after:
-1 -1 -1
4 5 6
7 8 9
-1 -1 -1
4 5 6
7 8 9
1385085408 32767 401515081
1 -1 -1
-1 -1 -1
変更されます。それはconstとして渡されるので、私には意味がありません。set()
はm3
でしか動作しません。何らかの形でm3
は、operator*
の最初の引数である行列に部分的に「束縛」されます。どうして?
右が、変異がどこから来るか、私はまだ 'm1'経験しながら、' 'だけm3'のために呼ばれている)('設定され、表示されません突然変異。 –
[最小限のテストケース](https://stackoverflow.com/help/mcve)を作成してください。 –
FWIWでも、私はここでreproすることはできません:http://ideone.com/7OZHXy –