I have a class that represents a diagonal matrix. I only store the elements along the diagonal, so I don't waste space with a bunch of 0's. However, I still want to be able to use double brackets to access elements in the array. To get around that, I use an inner class, like this:
template <class T>
class DiagonalMatrix
{
private:
const T ZERO = 0;
int _size;
Vector<T> _data;
class row
{
private:
DiagonalMatrix<T>* _parent;
int _row;
public:
row(DiagonalMatrix<T>* parent, const int row)
: _parent(parent), _row(row) {}
T& operator[](const int i);
};
class const_row
{
private:
const DiagonalMatrix<T>* const _parent;
int _row;
public:
const_row(const DiagonalMatrix<T>* const parent, const int row)
: _parent(parent), _row(row) {}
const T& operator[](const int i) const;
};
friend class row;
friend class const_row;
public:
row operator[] (const int i);
const const_row operator[] (const int i) const;
// other stuff
};
And here are the relevant definitions:
template<class T>
typename DiagonalMatrix<T>::row DiagonalMatrix<T>::operator[](const int i)
{
if (i < 0 || i >= _size)
{
throw IndexOutOfBoundsException(i);
}
return DiagonalMatrix<T>::row(this, i);
}
template <class T>
T& DiagonalMatrix<T>::row::operator[](const int i)
{
if (i < 0 || i >= _parent->_size)
{
throw IndexOutOfBoundsException(i);
}
if (row == col)
{
return _parent->_data[row];
}
// TODO Add a real exception
throw "Cannot modify non-diagonal elements";
}
With similar definitions for the const versions, except the const operator[] returns a reference to the constant ZERO instead of throwing for non-diagonal elements.
So here is my problem: The non-const version is being called even when I don't need to modify anything. For example, this throws my error string:
DiagonalMatrix<double> diag(5);
// fill in the diagonal elements with some values
cout << diag[0][2] << endl;
However, if I remove the non-const versions of the operator, it behaves as expected and outputs a 0.
I've also tried something like:
T& at(const int row, const int col);
const T& at(const int row, const int col) const;
// in main:
cout << diag.at(0, 2) << endl;
But this has the same issue. So I have two questions:
1) Why does C++ choose the non-const version of the function over the const version even when I am not assigning to the result? Doesn't operator<< typically pass the right-hand object by const&?
2) How can I get around this? I'd rather not have separate get() and set() functions if I can help it.
1) Why does C++ choose the non-const version of the function over the const version even when I am not assigning to the result? Doesn't operator<< typically pass the right-hand object by const&?
It choose the non-const version because diag is not a const object.
2) How can I get around this? I'd rather not have separate get() and set() functions if I can help it.
You can define a const refrence to diag and use it to print values:
const DiagonalMatrix<double> &const_diag = diag;
cout << diag[0][2] << endl; // call const version
Or you define a function to print values and pass a const reference in:
void show_diag(const DiagonalMatrix<double> &diag)
{
cout << diag[0][2] << endl; // call const version
}
show_diag(diag);
Related
Is it still undefined behavior to cast away const from a pointer to an object if only const methods are ever be called after the cast?
I'm trying to implement both an iterator and const_iterator for a class where the dereferenced iterator is a proxy object with a small amount of state and a pointer to the parent object (simplified below)
Although the const qualified proxy only calls const methods on the parent it still requires a non-const pointer in the constructor.
class query {
public:
int get (int r, int c) const;
void set (int r, int c, int v);
class iterator {
iterator (query *q, int r) : m_qry(q), m_row(r) {}
row operator* const () { return row(m_qry, m_row); }
query *m_qry;
int m_row;
};
class const_iterator {
const_iterator (const query *q, int r) : m_qry(q), m_row(r) {}
const row operator* const () {
// protected constructor for row needs cast
return row(const_cast<query *>(m_qry), m_row);
}
const query *m_qry;
int m_row;
};
iterator begin() { return iterator(this, 0); }
const_iterator begin() { return const_iterator(this, 0); }
};
class row {
friend query;
public:
int get (int col) const {
// can be called by both row and const row
return m_qry->get(m_row, col);
}
void set (int col, int v) {
// cannot be called for const row
return m_qry->set(m_row, col, v);
}
protected:
row (query *q, int row) : m_qry(q), m_row(r) {}
private:
query *m_qry;
int m_row;
};
I would prefer to avoid using different classes for the differing iterators as this would require considerable code duplication.
If this is not possible are there any other alternative design patterns with good performance?
In a const method, the this pointer is a const type.
So given that it's implicitly cast back to const, the behaviour is well defined.
There are 2 identical functions. One takes the argument with const keyword and another - without.
void A(const int* p);
void A(int* p);
int main()
{
int x;
A(&x);
return 0;
}
void A(const int* p)
{
cout << "2" << endl;
}
void A(int* p)
{
cout << "1" << endl;
}
Is it function overloading?
Why function without const will be called it my case?
Is it function overloading?
Yes. The two functions have the same name but different parameters, so they are overloads.
Why function without const will be called it my case?
Because x is not const. Try with a pointer to a const int, and you'll get the other overload:
const int y;
A(&y);
I think this is variation of the initial question :
from Stroustrup's tour of c++
template<typename T>
class C {
...
public:
...
T& operator[](int i);
const T& operator[](int i) const;
}
So as I understand it, the second method will target cases where the this-object is not intended to be modified.
I just wonder if the compiler is able to accurately guess that in every relevent case..
Why do it twice?
These 2 lines, why do it like this way? Is one enough?
inline T& operator() (int row, int col) { return this->m_data[row*NC + col]; }
const inline T& operator() (int row, int col) const { return this->m_data[row*NC + col]; }
thank you
*
* 2-DIMENSIONAL ARRAY
*
* Simulated by 1-dimension array.
******************************************************************************/
#ifndef __2D_ARRAY_H__
#define __2D_ARRAY_H__
#include <stdint.h>
#include <stdlib.h>
namespace alg {
/**
* 2D Array definition
*/
template <typename T=char>
class Array2D {
private:
uint32_t NR; // num of rows
uint32_t NC; // num of columns
T * m_data; // the place where the array resides.
public:
/**
* construct an array of size [nrow,col]
*/
Array2D(uint32_t nrow, uint32_t ncol) {
NR = nrow;
NC = ncol;
m_data = new T[nrow*ncol];
}
/**
* destructor
*/
~Array2D() {
delete [] m_data;
}
private:
Array2D(const Array2D&);
Array2D& operator=(const Array2D&);
public:
/**
* return number of rows of this array
*/
inline const uint32_t row() const { return NR; }
/**
* return number of columns of this array
*/
inline const uint32_t col() const { return NC; }
/**
* return the value by the given (row, col);
*/
inline T& operator() (int row, int col) { return this->m_data[row*NC + col]; }
const inline T& operator() (int row, int col) const { return this->m_data[row*NC + col]; }
inline T* operator[] (int row) { return &(m_data[row * NC]); }
inline const T* operator[] (int row) const { return &(m_data[row * NC]); }
/**
* clear the array by a given value
*/
void clear(const T & value) {
for(uint32_t i=0; i<NR*NC;i++){
m_data[i] = value;
}
}
};
}
#endif //
One is const and the other is not.
The difference is that when you have a const reference to a Array2D you're only allowed to call member functions marked const. In this case that means the 2nd version, where it must necessarily return a const reference to the element it holds.
If you have a non-const reference, though, that 2nd version means you can't use operator() to make any changes to your Array2D.
If you look at standard library containers like std::vector you'll see that they do the same thing. You can get an iterator from begin() and a const_iterator from begin() const.
The first, non-constant version returns a reference that can be modified. If you have a constant object, you still want to be able to at least read the value, so you have to provide a second constant version.
The two () operators are not the same. inline T& operator() (int row, int col); returns a reference that allows the returned value to be modified. const inline T& operator() (int row, int col) const returns a reference that disallows the returned value from being modified. Also if the calling object is a const alg::Array2D&, than it can ONLY use the const operator();. So in order to allow users of the Array2D class to properly use const objects. It is best practice to implement both signatures for the operator ().
You could have a function void make_something (const Array2D<char> &input, Array2D<char> &output). This function lets input untouched, makes some operation with it, and writes the result to output. Reading from input would only be possible if there is also a const operator.
inline T& operator() (int row, int col) { return this->m_data[row*NC + col]; }
returns a non-const reference to the data in m_data[row * NC + col], which means I can do
auto& ref = obj(x, y);
ref = BAD_DATA;
and your object can't stop me. The const variant protects against this, and can be fingerprinted as const because it has no side effects on the object as a result.
inline const T& operator() (int row, int col) const { return this->m_data[row*NC + col]; }
This allows me to propagate constness outwards:
void myFunc(const Object& obj) /* I'm only going to look */
{
const auto& ref = obj(x, y);
std::cout << x << ',' << y << " = " << ref << '\n';
}
Let's say I have something like the following method in my container class:
Datatype& operator[](const unsigned int Index) // I know this should use size_t instead.
{
return *(BasePointer + Index); // Where BasePointer is the start of the array.
}
I'd like to implement some sort of bounds-checking for the MyInstance[Index] = Value usage so the container resizes automatically if the user tries to change a value outside its range. However, I want something else to happen if the user tries to access a value outside the container's range, e.g. MyVariable = MyInstance[Index]. How can I detect how operator[] is being used?
Sketch:
return a proxy object instead of the actual data entry. The proxy object then defines operator = to handle the assignment case, and an implicit conversion operator for the reading-out case.
template <typename T>
class AccessorProxy {
friend class Container<T>;
public:
AccessorProxy(Container<T>& data, unsigned index)
: data(data), index(index) { }
void operator =(T const& new_value) {
// Expand array.
}
operator const T&() const {
// Do bounds check.
return *(data.inner_array + index);
}
private:
AccessorProxy(const AccessorProxy& rhs)
: data(rhs.data), index(rhs.index) {}
AccessorProxy& operator=(const AccessorProxy&);
Container<T>& data;
unsigned index;
};
template <typename T>
class ConstAccessorProxy {
friend class Container<T>;
public:
ConstAccessorProxy(const Container<T>& data, unsigned index)
: data(data), index(index) { }
operator const T&() const {
// Do bounds check.
return *(data.inner_array + index);
}
private:
ConstAccessorProxy(const ConstAccessorProxy& rhs)
: data(rhs.data), index(rhs.index) {}
ConstAccessorProxy& operator=(const ConstAccessorProxy&);
const Container<T>& data;
unsigned index;
};
AccessorProxy<Datatype> operator[](const unsigned int Index)
{
return AccessorProxy<Datatype>(*this, Index);
}
ConstAccessorProxy<Datatype> operator[] const (const unsigned int Index)
{
return ConstAccessorProxy<Datatype>(*this, Index);
}
The accessor classes will likely need to be be friends of the container class.
Finding ways to avoid the code duplication is left as an exercise to the reader. :)
Use a dummy class type to represent expressions like MyInstance[Index] and delay figuring out what to do until that expression is used.
class MyContainer {
private:
class IndexExpr {
public:
// Get data from container:
operator const Datatype&() const;
// Expand container if necessary, then store data:
Datatype& operator=(const Datatype& value);
// Treat MyInstance[i] = MyInstance[j]; as expected:
Datatype& operator=(const IndexExpr& rhs)
{ return *this = static_cast<const Datatype&>(rhs); }
private:
IndexExpr(MyContainer& cont, unsigned int ind);
MyContainer& container_;
unsigned int index_;
friend class MyContainer;
};
public:
IndexExpr operator[](unsigned int Index)
{ return IndexExpr(*this, Index); }
// No IndexExpr needed when container is const:
const Datatype& operator[](unsigned int Index) const;
// ...
};
This is not a perfect answer to "how to detect", but, if the user is accessing the operator[] via a const instance, then throw an exception if the index is out of bounds.
i.e.
Datatype const& operator[]() const { .. // don't modify here, throw exception
However, if the user is accessing the instance via a non const instance, then by all means expand if the index is out of bounds (and within your acceptable ranges)
Datatype& operator[]() { .. // modify here
Basically, you are using the const attribute of the instance to determine what your semantics would be (as done in std::map - i.e. trying to call operator[] on a const instance of a map results in a compiler error - i.e. there is no const qualified operator[] for map, because the function is guaranteed to create a mapping if the key does not exist already.)
Let's say I have a container class called MyContainerClass that holds integers.
The [] operator, as you know, can be overloaded so the user can more intuitively access values as if the container were a regular array. For example:
MyContainerClass MyInstance;
// ...
int ValueAtIndex = MyInstance[3]; // Gets the value at the index of 3.
The obvious return type for operator[] would be int, but then the user wouldn't be able to do something like this:
MyContainerClass MyInstance;
MyInstance[3] = 5;
So, what should the return type for operator[] be?
The obvious return type is int& :)
For increased elaboration:
int &operator[](ptrdiff_t i) { return myarray[i]; }
int const& operator[](ptrdiff_t i) const { return myarray[i]; }
// ^ could be "int" too. Doesn't matter for a simple type as "int".
This should be a reference:
int &
class MyContainerClass {
public:
int& operator[](unsigned int index);
int operator[](unsigned int index) const;
// ...
};
Returning a reference lets the user use the result as an lvalue, as in your example MyInstance[3] = 5;. Adding a const overload makes sure they can't do that if MyInstance is a const variable or reference.
But sometimes you want things to look like that but don't really have an int you can take a reference to. Or maybe you want to allow multiple types on the right-hand side of MyInstance[3] = expr;. In this case, you can use a dummy object which overloads assignment:
class MyContainerClass {
private:
class Index {
public:
Index& operator=(int val);
Index& operator=(const string& val);
private:
Index(MyContainerClass& cont, unsigned int ind);
MyContainerClass& m_cont;
unsigned int m_ind;
friend class MyContainerClass;
};
public:
Index operator[](unsigned int ind) { return Index(*this, ind); }
int operator[](unsigned int ind) const;
// ...
};
int&
returning a reference allows you too use the returned value as a left-hand side of the assignment.
same reason why operator<<() returns an ostream&, which allows you to write cout << a << b;