簡體   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