繁体   English   中英

C ++相同的代码永远不会在Visual Studio中编译/运行,有时甚至不会在Qt Creator中运行

[英]c++ same code compiles/runs never in Visual Studio and sometimes in Qt Creator

当我注意到以下问题时,我正在进行一些c ++练习。 给定的代码将无法在Visual Studio 2013或Qt Creator 5.4.1中运行/编译

给出错误:

invalid types 'double[int]' for array subscript
test[0][0] = 2;
         ^

但是,当您第一次从double &operator[];更改头文件中的第16行(和第17行double &operator[]; double operator[]并在源文件中进行相同的更改->然后进行编译(同时出现多个错误)->最后将其更改回原始的double &operator[]; 然后在Qt Creator 5.4.1中它将编译并在给出预期结果的同时运行。

编辑:这并不总是有效,但是将其更改为double *operator[]而不是double operator[]总是会重现该问题。

为什么会这样呢?

matrix.h

#ifndef MATRIX_H
#define MATRIX_H

#include <iostream>

using namespace std;

class Matrix
{
private:
    double** m_elements;
    int m_rows;
    int m_columns;
public:
    Matrix(int rows = 1, int columns = 1);
    double &operator[](int index);
    const double &operator[](int index) const;
    friend ostream &operator<<(ostream &ostr, Matrix matrix);
};

#endif // MATRIX_H

matrix.cpp

#include "matrix.h"

Matrix::Matrix(int rows, int columns)
{
    m_rows = rows;
    m_columns = columns;
    m_elements = new double*[rows];
    for(int i=0; i<rows; i++)
    {
        m_elements[i] = new double[columns];
        for(int j=0; j<columns; j++)
            m_elements[i][j] = 0;
    }
}

double &Matrix::operator[](int index)
{
    return *(m_elements[index]);
}

const double &Matrix::operator[](int index) const
{
    return *(m_elements[index]);
}

ostream &operator<<(ostream &ostr, Matrix matrix)
{
    for(int i=0; i<matrix.m_rows; i++)
    {
        for(int j=0; j<matrix.m_columns; j++)
        {
            ostr << matrix.m_elements[i][j] << " ";
        }
        ostr << "\n";
    }
    return ostr;
}

主要

#include <iostream>
#include "matrix.h"

using namespace std;

int main()
{
    Matrix test(4,4);
    test[0][0] = 2;
    cout << test;

    return 0;
}
double &Matrix::operator[](int index)
{
    return *(m_elements[index]);
}

将返回对列中第一个元素而不是该列的引用。 因此,调用test[0][0] = 2; 尝试将[]运算符应用于double,而不是double数组。

快速解决方案:

double * & Matrix::operator[](size_t index)
{
    return m_elements[index];
}

这将返回对指针的引用(请继续阅读以找出为什么要打扰该引用),并且可以在返回的指针上使用[]来获取数据元素。

但...

有更好的方法可以做到这一点。

如果可能,请使用std :: vector而不是动态数组。

std::vector<std::vector<double> > m_elements(m_rows, std::vector<double>(m_columns, 0.0));

这将解决很多潜在的问题,并且一次将矩阵初始化为0。 它不会解决[] []索引。 这仍然需要一些工作。

进行索引的最简单,最安全的方法是完全不使用[]运算符。 而是定义一个新方法。 这样,您可以完全控制公开的内容,并且可以在超出范围之前完全测试输入的有效性。

double &Matrix::at(size_t row, size_t column) 
{
    // optional overrun defence if desired
    if (row < m_rows || column < m_columns)
    {
        return m_elements[row][column]; 
    } 
    throw std::out_of_range("Matrix indices out of range");
}
double Matrix::at(size_t row, size_t column) const
{
    // put overrun defence here if desired
    return m_elements[row][column]; 
}
matrix.at(2,3) = 2;
constmatrix.at(2,3) = 2; // bad lvalue compiler error

注意使用size_t代替int size_t是无符号的,不需要对负数进行有效性检查。 您不能有一个负数组索引,那么为什么要允许这种可能性呢?

还值得注意的是,这种方法可以轻松地将矩阵的存储定义为一维数组,如下所示:

std::vector<double> m_elements(m_rows * m_columns, 0.0);

或者如果您必须使用数组

double m_elements = new double[m_rows* m_columns];

并像这样访问它:

double &Matrix::at(size_t row, size_t column) 
{
    return m_elements[row * m_rows + column]; 
}

为什么? 有很多很好的理由。 对我来说,创建,维护和清理一个对象比m_rows +1更容易。 另一个极好的原因是本地性。 整个矩阵都保证在一个连续的块中,而不是这里的一个数组,那里的另一个数组,以及另一个相当于Marianas Trench底部的RAM中的数组。 高速缓存命中率(从而提高性能)的几率上升。

如果您更喜欢数组的外观,那么operator()重载就非常接近了。

double &Matrix::operator()(size_t row, size_t column) 
{
    return m_elements[row][column];
 }
double Matrix::operator()(size_t row, size_t column) const
{
    return m_elements[row][column];
}
matrix(2,3) = 2;

如果您必须具备[] []

建议的[]运算符形式返回对索引数据的引用,在这种情况下为向量或行数组指针。

std::vector<double> & Matrix::operator[](size_t index)
{
    return m_elements[index];
}

要么

double * & Matrix::operator[](size_t index)

数组和向量内部是相同的。

警告:这使用户可以使用返回的向量或指针引用来解决各种麻烦。 考虑matrix[0].clear(); matrix[0] = NULL; 例如。

double * Matrix::operator[](size_t index)

将通过返回指针的副本来防止大多数滥用。 不幸的是,这样做不能保护矢量,因为矢量的副本将是与源内容的副本完全不同的矢量。 更新它并期望持久性将是徒劳的。 向量必须在包装器类中对用户隐藏,并且这正迅速成为过多的工作。

此外,返回副本或包装器也将阻止对引用的合法使用,并违反“最少惊讶法则”:Matrix []运算符的工作方式与其他[]运算符不同,并且如果不加怀疑的编码器可能会导致意外行为使用它作为常规[]运算符。

我的意见是返回未受保护的引用,并且如果使用Matrix类的任何人都想对自己开枪……那么,您只能做很多事情。 如果必须保护用户,请使用上述的at方法或operator()方法。

向量的Const []运算符相似

std::vector<double> const & Matrix::operator[](size_t index) const

但对于数组而言有所不同,因为指针和指向的值都应为const

double const * const & Matrix::operator[](size_t index) const

我建议的实现:

Matrix.h

#ifndef MATRIX_H
#define MATRIX_H

#include <iostream>
#include <vector>

// note that the using namespace std; is gone. One should never put it in the header
// and one should also think hard about putting it in the implementation file
class Matrix
{
private:
    std::vector<double> m_elements;
    size_t m_rows;
    size_t m_columns;
public:
    Matrix(int rows = 1, int columns = 1);

    double &operator()(size_t row, size_t column);

    double operator()(size_t row, size_t column) const;

    friend std::ostream &operator<<(std::ostream &ostr, const Matrix & matrix);
};

#endif // MATRIX_H

Matrix.cpp

#include <stdexcept>
#include "Matrix.h"

Matrix::Matrix(int rows, int columns):
        m_elements(rows * columns, 0.0),
        m_rows(rows),
        m_columns(columns)
{
}

std::ostream &operator<<(std::ostream &ostr, const Matrix &matrix)
{
    for(size_t i=0; i<matrix.m_rows; i++)
    {
        for(size_t j=0; j<matrix.m_columns; j++)
        {
            ostr << matrix(i,j) << " ";
        }
        ostr << std::endl;
    }
    return ostr;
}

double &Matrix::operator()(size_t row, size_t column)
{
    if (row < m_rows && column < m_columns)
    {
        return m_elements[row * m_rows + column];
    }
    throw std::out_of_range("Matrix indices out of range");
 }

double Matrix::operator()(size_t row, size_t column) const
{
    if (row < m_rows && column < m_columns)
    {
        return m_elements[row * m_rows + column];
    }
    throw std::out_of_range("Matrix indices out of range");
}

只是因为回报的意义。

当您返回Reference & ,可以根据需要进行更改,例如test[2][2] = 2; 因为这将使它回到它曾经提到的源头

当您按值返回时,它只是一个临时对象,使用后将被销毁,这意味着您无法更改它!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM