c++ same code compiles/runs never in Visual Studio and sometimes in Qt Creator -


i making of c++ exercises when noticed following problem. given code not run/compile in visual studio 2013 or qt creator 5.4.1

giving error:

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

however when first change 16th (and 17th) line in header file double &operator[]; double operator[] , make same changes in source files -> compile (while getting multiple errors) -> , lastly changing original double &operator[];. in qt creator 5.4.1 compile , run while giving expected results.

edit: not work, changing double *operator[] instead of double operator[] reproduce problem.

why happening?

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

main

#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]); } 

will return reference first element in column rather column. calling test[0][0] = 2; tries apply [] operator double, not array of double.

quick solution:

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

this returns reference pointer (read on find out why bother reference) , can use [] on returned pointer data element.

but...

there better ways this.

use std::vector, if possible, instead of dynamic array.

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

this solve lot of potential problems , initializing of matrix 0 in 1 shot. won't solve [][] indexing though. still take bit of work.

the simplest , safest way indexing not use [] operator @ all. instead define new method. way have total control on exposed, , input can tested validity before running out of bounds.

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 

note use of size_t in place of int. size_t unsigned , removes need validity check negative numbers. can't have negative array index, why allow possibility?

it worth noting approach makes easy define storage matrix 1 dimensional array this:

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

or if have use array

double m_elements = new double[m_rows* m_columns]; 

and access this:

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

why? number of reasons. easier create, maintain , clean 1 object m_rows +1 enough reason me. excellent reason locality. whole matrix guaranteed in 1 contiguous block, not 1 array here, there, , yet in ram equivalent of bottom of marianas trench. odds of cache hits (and performance) go way up.

if prefer , feel of array, operator() overload comes quite close.

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; 

if must have [][]

the suggested form of [] operator returns reference indexed data, in case vector or pointer row array.

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

or

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

the array , vector internals identical.

caveat: allows user sorts of trouble returned vector or pointer reference. consider matrix[0].clear(); or matrix[0] = null; example.

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

will prevent abuse returning copy of pointer. unfortunately cannot done protect vector because copy of vector different vector copies of source's contents. updating , expecting persistence futile. vector have hidden user inside wrapper class, , rapidly becoming work.

in addition, returning copy or wrapper block legitimate uses of reference , violates law of least surprise: matrix [] operator not work same other [] operators , may result in unexpected behaviour if unsuspecting coder uses regular [] operator.

my opinion return unprotected references, , if whoever using matrix class wants shoot in head... well, can much. if have protect user, use at method or operator() approach described above.

const [] operators similar vector

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

but different array because both pointer , values pointed @ should const

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

my suggested implementation:

matrix.h

#ifndef matrix_h #define matrix_h  #include <iostream> #include <vector>  // note using namespace std; gone. 1 should never put in header // , 1 should think hard putting in 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"); } 

Comments

Popular posts from this blog

dns - How To Use Custom Nameserver On Free Cloudflare? -

python - Pygame screen.blit not working -

c# - Web API response xml language -