2017-07-16 47 views
0

我遇到了一些我無法輕易向自己解釋的奇怪副作用。可能我錯過了一些非常明顯的東西,但我現在已經查找了幾個小時的錯誤,並且代碼非常簡單,所以我得出結論,我必須對某些東西有一些根本性的誤解。對嵌套陣列類型的常量變量的副作用

考慮以下代碼,這是爲了計算兩個二維矩陣(的產品,我已經改變了set()函數添加-1的說法細胞,使調試輸出更容易理解。

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; 
    } 
}; 

由於你可以看到,getter函數要麼返回一個副本或常量引用的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*的第一個參數的矩陣。爲什麼?

+0

正確的,但我仍然看不到其中的變異來源,爲'的set()'只要求'm3'而'm1'經驗突變。 –

+1

請構建一個[最小測試用例](https://stackoverflow.com/help/mcve)。 –

+0

儘管FWIW,我不能在這裏重新報價:http://ideone.com/7OZHXy –

回答

0

由於ij都過早增加,所以您正在寫出循環中的界限。

的代碼應該是這樣的:

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); 

     j++; // <-- 
    } 

    i++; // <-- 
} 
+0

哈哈,謝謝。我知道這會是一件愚蠢的事情。 –