【问题标题】:side effects on constant variable of nested array type [closed]对嵌套数组类型的常量变量的副作用 [关闭]
【发布时间】:2017-07-16 00:02:49
【问题描述】:

我遇到了我无法对自己解释的奇怪副作用。可能我遗漏了一些非常明显的东西,但是我已经找了几个小时了,代码很简单,所以我得出结论,我一定对……有些东西有一些相当基本的误解。

考虑一下这段代码,它旨在计算两个二维矩阵的乘积(我已更改 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* 的第一个参数。为什么?

【问题讨论】:

  • 对,但我仍然看不到突变来自哪里,因为 set() 仅被称为 m3m1 经历突变。
  • 请构造一个minimal test case
  • 虽然 FWIW,但我不能在这里复制:ideone.com/7OZHXy
  • 对我来说似乎是一个常见的错字,投票结束。
  • 我可以自己关闭吗?

标签: c++ constants side-effects


【解决方案1】:

因为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++; // <--
}

【讨论】:

  • 大声笑,谢谢。我就知道会是这样的蠢事。
猜你喜欢
  • 2011-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-03
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
  • 2016-11-05
相关资源
最近更新 更多