I have a class which allows me to access a vectors value:
Class Image{
public:
Image(int rows, int cols): cols_(cols), rows_(rows), data_(rows*cols,0) {};
int& at(int row, int col){
return data_.at(col*row);
};
private:
int rows_ = 0;
int cols_ = 0;
const int max_val_ = 255;
std::vector<int> data_;
Currently this lets me perform
int num = image.at(row, col);
// or
image.at(row, col) = 10;
My question is how to I limit the values of data_ to not allow an assignment more than max_value_? I.e image.at(row,col) = 256;
Like Max Langhof said, you can use a proxy object like this:
class AssignmentProxy
{
public:
AssignmentProxy(int& value, int min, int max) : value_(value), min_(min), max_(max) { }
AssignmentProxy& operator=(int value)
{
if (value >= min_ && value < max_)
value_ = value;
else
throw std::invalid_argument("no");
return *this;
}
operator int() const noexcept
{
return value_;
}
private:
int min_, max_;
int& value_;
};
The implicit conversion to int is questionable but justified I think, since this only a proxy that mimics an integer.
Here is a full example.
Related
I'm having a problem to make the code:
void main(){
Matrix c(rows,cols);//rows & cols are int numbers
c[0][0]=2//the line that I'm having a problem to do the operator
}
//My class defined like this:
class Matrix{
public:
Matrix(int rows,int cols): rows(rows), cols(cols){
mat= new double*[cols];
for( int i=0; i<rows;i++){
*mat=new double[i];
}
}
private:
int rows,cols;
double **mat;
};
How can I make an operator that will help me to do the line that I'm having a problem with?
There are no operator [][], but operator[]. So that one should return something for which you can use [] too (pointer or proxy class).
In your case, you might simply do:
double* operator[](int i) { return mat[i]; }
const double* operator[](int i) const { return mat[i]; }
For more complicated cases, you have to return a proxy class.
Don't dynamically allocate in two dimensions like that. It's poison for your cache, and completely pointless. I see it all the time and I wish I didn't! Make yourself a nice std::vector<double> of size rows*cols instead.
Anyway, the trick to permit [width][height] is a proxy class. Have your operator[] return an instance of a class that has its own operator[] to do the second-level lookup.
Something like this:
#include <iostream>
#include <vector>
struct Matrix
{
Matrix(const size_t columns, const size_t rows)
: columns(columns)
, rows(rows)
, data(columns*rows, 0)
{}
size_t index(const size_t x, const size_t y) const
{
return x + y*columns;
}
double& at(const size_t x, const size_t y)
{
return data[index(x, y)];
}
double at(const size_t x, const size_t y) const
{
return data[index(x, y)];
}
template <bool Const>
struct LookupHelper
{
using ParentType = std::conditional_t<Const, const Matrix, Matrix>;
using ReturnType = std::conditional_t<Const, double, double&>;
LookupHelper(ParentType& parent, const size_t x) : parent(parent), x(x) {}
ReturnType operator[](const size_t y)
{
return parent.data[parent.index(x, y)];
}
const ReturnType operator[](const size_t y) const
{
return parent.data[parent.index(x, y)];
}
private:
ParentType& parent;
const size_t x;
};
LookupHelper<false> operator[](const size_t x)
{
return {*this, x};
}
LookupHelper<true> operator[](const size_t x) const
{
return {*this, x};
}
private:
const size_t columns, rows;
std::vector<double> data;
};
int main()
{
Matrix m(42, 3);
m[15][3] = 1;
std::cout << m[15][3] << '\n';
}
(In reality, you'd want to make it moveable and it could doubtlessly be tidied up a bit.)
Certainly, switching to operator() or a .at(width, height) member function is a lot easier…
i'm making a simple map with defined size as parameter, i would like it to be stored in my private member variable.
I will show a simple exemple :
class A {
public:
A (const int size) {
map_size_ = size;
//or | both will not compile
int map[size][size];
}
private:
int map_size_;
int map_[map_size_][map_size_];
}
I know the map_ won't compile, but i wonder how to declare it properly with a const int from the constructor parameter and without pointers.
You should use std::vector
#include <vector>
class A {
public:
explicit A (const int size) {
map_.resize(size);
for (auto &v : map_) v.resize(size);
}
private:
std::vector<std::vector<int>> map_;
};
This might not be the most optimal way from performance point of view, but it is the simplest one. There is no way around that. int[][] declarations do not work with non-compile time values in C++.
Tips:
Use explicit with single argument constructors.
You should use std::size_t instead of int for sizes.
This should work:
class A {
public:
A(int const size) {
_map_size = size;
_map = new int[_map_size * _map_size];
}
private:
int _map_size;
int* _map;
};
UPDATE - apparently people want a more comprehensive solution than the OP asked about.
class A {
public:
A(int const size)
: _map_size(size)
, _map(new int[_map_size * _map_size]) {
}
A(A const&) = delete;
~A() {
delete[] _map;
}
A& operator=(A const&) = delete;
int at(int x, int y) const {
if (x < 0 || x >= _map_size || y < 0 || y >= _map_size)
throw "That coordinate is in the giggleweeds";
return _map[y * _map_size + x];
}
int set_at(int x, int y, int value) {
if (x < 0 || x >= _map_size || y < 0 || y >= _map_size)
throw "That coordinate is in the giggleweeds";
_map[y * _map_size + x] = value;
}
private:
int _map_size;
int* _map;
};
been stuck at this for a while. I have a mathlibrary with a 3x3 matrix class. It used to be dynamic , using a pointer and allocating memory of creation. But as its always gonna be 3x3 I decided to change it, but now I cant use [][] to get values of my array. I am using a proxy class!
class mat3 {
private:
double arr[3][3];
public:
mat3();
mat3(double, double, double, double, double,
double, double, double, double);
//Proxy class
class Proxy {
private:
double arr[3];
public:
Proxy(const double _arr[3]) { arr = _arr; }
double& operator[] (const int index) {
return arr[index];
}
const double& operator[] (const int index) const{
return arr[index];
}
};
const Proxy operator[] (const int index) const{
return Proxy(arr[index]);
}
Proxy operator[] (const int index) {
return Proxy(arr[index]);
}
Now where arr = _arr i get a compiler error: Error: Expression must be a modifiable Ivalue
What am I doing wrong? How am I suposed to achieve this?
When you pass an array as a parameter, it gets converted to a pointer, so your constructor is the same as Proxy(const double *_arr) { arr = _arr; } and that's illegal.
Besides, you want to return a reference to the original values in mat3. So change Proxy to use a pointer to double instead:
class Proxy {
private:
double *arr;
...
};
Surprisingly this works (I wasn't expecting it to):
#include <iostream>
struct matrix
{
typedef double ((&reference)[3])[3]; // define a reference type to a 3x3 array
double array[3][3];
operator reference() // implicit conversion to 3x3 array reference
{
return array;
}
void dump()
{
for(unsigned x = 0; x < 3; ++x)
for(unsigned y = 0; y < 3; ++y)
std::cout << array[x][y] << '\n';
}
};
int main()
{
matrix m;
for(unsigned x = 0; x < 3; ++x)
for(unsigned y = 0; y < 3; ++y)
m[x][y] = x * y; // seems to work okay!!!
m.dump();
}
You don't need Proxy class, you may just do:
class mat3
{
using row_type = double [3];
public:
mat3();
mat3(double, double, double, double, double, double, double, double, double);
const row_type& operator[](const int index) const { return arr[index]; }
row_type& operator[](const int index) { return arr[index]; }
private:
row_type arr[3]; // or double arr[3][3];
};
Note also that using std::array<std::array<double, 3>, 3> arr; would be more intuitive to edit code that C-array.
If really you want to have your Proxy class, you may use:
class mat3
{
using row_type = double[3];
public:
mat3();
mat3(double, double, double, double, double, double, double, double, double);
class Proxy
{
private:
row_type& arr; // or double (&arr)[3];
public:
explicit Proxy(row_type& arr) : arr(arr) {}
double& operator[](const int index) { return arr[index]; }
const double& operator[](const int index) const { return arr[index]; }
};
const row_type& operator[](const int index) const { return arr[index]; }
row_type& operator[](const int index) { return arr[index]; }
private:
row_type arr[3]; // or double arr[3][3];
};
There is something that is troubling my brain since a moment: I am trying to overload the [] operator based on the return type. Here is what I need to do:
class A {
private:
double* data_;
int N_;
public:
A (N=0):N_(N){
data_ = new double[N];
}
~A {delete[] data_;}
double operator[] (const int i) {
return data_[i];
}
double* operator[] (const int i) {
return &data[i]; // for example; in fact here i need to return some block of data_
}
};
This code won't compile; and that is my problem. Can someone help me to solve this problem?
PS: I know how to overload normal functions on the return type for example:
int foo ();
string foo ();
I used some tricks that I read in this forum. In this way:
struct func {
operator string() { return "1";}
operator int() { return 2; }
};
int main( ) {
int x = func(); // calls int version
string y = func(); // calls string version
double d = func(); // calls int version
cout << func() << endl; // calls int version
func(); // calls neither
}
Thank you.
Two method overloads must have different signatures. The return type is not part of the signature of a method.
You can use the same "trick" that you use for functions, that is use a proxy object with conversion operators:
class A
{
private:
double* data_;
int N_;
public:
A (int N = 0)
: N_(N), data_(new double[N])
{}
~A() { delete[] data_; }
struct proxy
{
int i;
double * data;
operator double() const
{
return data[i];
}
operator double*()
{
return &data[i];
}
operator double const *() const
{
return &data[i];
}
};
proxy operator[] (int const i) {
proxy p { i, data_ };
return p;
}
proxy const operator[] (int const i) const {
proxy p { i, data_ };
return p;
}
};
int main()
{
{
A a(12);
double d = a[0];
double * pd = a[0];
}
{
A const ca(12);
double d = ca[0];
//double * pd = ca[0]; // does not compile thanks to overloads on const
double const * pcd = ca[0];
}
}
However, I would argue that this is a terrible idea. Having your operator[] return either a value or a pointer to this value is guaranteed to confuse the users of your class, in addition to making it impractical to use in expressions where both types are possible. For instance, std::cout << a[0]; would not compile (ambiguous overloads).
Probably you need something like that:
class A {
private:
double* data_;
int N_;
... // other stuff
public:
double operator[] (const int i) const { // note const here
return data_[i];
}
double& operator[] (const int i) { // note reference here
return data_[i];
}
};
also operator should be public to have a sense.
A while ago, I found in a website some code examples of utility functions that are used when creating, destructing objects, or even when overloading some of their operators.
More precisely, the following member functions are mainly used: init, copy, set, and destroy.
The init member function is used to initialize all the private members. It's mostly called inside the constructors, e.g. the default or parameter constructor.
The copy member function is used to do a deep copy of an object passed as a const reference. It is called inside the reference constructor and the overload of the operator =.
The set member function which mainly allocates memory for the private members that require it.
Finally, the destroy member function is used for releasing the allocated memory. It's called, for example, inside of the destructor.
I would like to have your opinion and know if this is a good programming practice? Which are the benefits or drawbacks? Any comments and suggestions are welcomed!
Below, I'm illustrating how those member functions are defined for a CMatrix<T> class.
matrix.h
template < class T >
class CMatrix{
CMatrix(){ this->initMatrix(); }
CMatrix(int nRows, int nCols, int nChannels){
this->initComplexMatrix();
this->setComplexMatrix(nRows, nCols, nChannels);
}
CMatrix(const CMatrix<T> & refMatrix){
this->initComplexMatrix();
this->copyComplexMatrix(refMatrix);
}
CMatrix<T> & operator = (const CMatrix<T> & refMatrix){
if(this!=&refMatrix){
this->destroyComplexMatrix();
this->initComplexMatrix();
this->copyComplexMatrix(refMatrix);
}
return (*this);
}
T & CMatrix<T>::operator()(int, int, int);
T CMatrix<T>::operator()(int, int, int) const;
......
void initMatrix();
void copyMatrix(const CMatrix<T> & );
void setMatrix(int, int, int = 1);
void destroyMatrix();
......
~CMatrix(){ this->destroyMatrix(); }
private:
T *** m_pData;
int m_nRows;
int m_nCols;
int m_nChannels;
};
matrix.cpp
#include <matrix.h>
template < class T >
inline T & CMatrix<T>::operator()(int mrow, int mcol, int mchannel){
assert(mrow >= 0 && mrow < this->getRows());
assert(mcol >= 0 && mcol < this->getCols());
assert(mchannel >= 0 && mchannel < this->getChannels());
return this->m_pData[mrow][mcol][mchannel];
}
template < class T >
void CMatrix<T>::initMatrix(){
this->m_nRows = 0;
this->m_nCols = 0;
this->m_nChannels= 0;
this->m_pData = NULL;
}
template < class T >
void CMatrix<T>::copyMatrix(const CMatrix<T> & refMatrix){
if(refMatrix.m_pData!=NULL){
this->setMatrix(refMatrix.getRows(), refMatrix.getCols(), refMatrix.getChannels());
for(register int dy=0; dy < this->getRows(); dy++){
for(register int dx=0; dx < this->getCols(); dx++){
for(register int ch=0; ch < this->getChannels(); ch++){
this->m_pData[(dy)][(dx)][(ch)] = refMatrix.m_pData[(dy)][(dx)][(ch)];
}
}
}
}
else{
this->m_pData = NULL;
}
}
template < class T >
void CMatrix<T>::setMatrix(int nRows, int nCols, int nChannels){
this->destroyMatrix();
this->m_pData = NULL;
this->m_pData = new T ** [nRows];
for(register int dy=0; dy < nRows; dy++){
this->m_pData[dy] = NULL;
this->m_pData[dy] = new T * [nCols];
for(register int dx=0; dx < nCols; dx++){
this->m_pData[dy][dx] = NULL;
this->m_pData[dy][dx] = new T[nChannels];
}
}
this->setRows(mrows);
this->setCols(mcols);
this->setChannels(mchannels);
}
template < class T >
void CMatrix<T>::destroyMatrix(){
if(this->m_pData!=NULL){
for(register int dy=0; dy < this->getRows(); dy++){
for(register int dx=0; dx < this->getCols(); dx++){
delete [] this->m_pData[dy][dx];
}
delete [] this->m_pData[dy];
}
delete [] this->m_pData;
this->m_pData = NULL;
}
}
No, this is not recommended. The way you propose is not exception safe and is not compatible with const or subobjects that need non-default construction.
Instead use the ctor-initializer-list. Code reuse can be achieved through static helper functions called in the ctor-initializer-list or by moving logic into subobject constructors.
For memory allocation, use a subobject per resource. The memory management logic ends up in the subobject constructor and destructor. In many cases, you can use existing RAII classes from the library, such as std::vector, and not need to write any memory management code yourself.
Most operators can reuse the logic in the constructors, using the copy-and-swap idiom.
EDIT: Exception-safe construction might look something like this:
#include <vector>
template<typename T>
class matrix
{
int m_nCols;
std::vector<T*> m_rows;
std::vector<T> m_cells;
size_t makeIndex( int row, int col ) const { return row*m_nCols + col; }
public:
matrix( int nRows, int nCols )
: m_nCols(nCols), m_rows(nRows), m_cells(nRows * nCols)
{
while (nRows--) m_rows[nRows] = &m_cells[nRows * nCols];
}
matrix( const matrix<T>& other )
: m_nCols(other.m_nCols), m_rows(other.m_rows.size()), m_cells(other.m_cells)
{
int nRows = other.m_rows.size();
while (nRows--) m_rows[nRows] = &m_cells[nRows * nCols];
}
void swap( matrix& other )
{
using std::swap;
swap(m_nCols, other.m_nCols);
swap(m_rows, other.m_rows);
swap(m_cells, other.m_cells);
}
matrix& operator=( matrix other )
{
other.swap(*this);
return *this;
}
const T& operator()( int row, int col ) const { return m_cells[makeIndex(row,col)]; }
T& operator()( int row, int col ) { return m_cells[makeIndex(row,col)]; }
};
The std::vector destructor will take care of freeing the memory, and since the two allocations are separate objects, if m_cells fails to allocate its memory, the destructor for m_rows will run and nothing will leak.
Of course, std::vector is a little bit overkill here, a fixed-size array RAII class would be sufficient. But std::auto_ptr can't be used with arrays. I think C++0x is supposed to add a standard fixed-size RAII array class.
EDIT: Per request, a 3-D version:
#include <vector>
template<typename T>
class cube
{
int m_nCols, m_nRows;
std::vector<T> m_cells;
size_t makeIndex( int row, int col, int channel ) const { return (channel*m_nRows + row)*m_nCols + col; }
public:
cube( int nRows, int nCols, int nChannels )
: m_nCols(nCols), m_nRows(nRows), m_cells(nRows * nCols * nChannels)
{
}
cube( const cube<T>& other )
: m_nCols(other.m_nCols), m_nRows(other.m_nRows), m_cells(other.m_cells)
{
}
void swap( cube& other )
{
using std::swap;
swap(m_nCols, other.m_nCols);
swap(m_nRows, other.m_nRows);
swap(m_cells, other.m_cells);
}
cube& operator=( cube other )
{
other.swap(*this);
return *this;
}
const T& operator()( int row, int col, int channel ) const { return m_cells[makeIndex(row,col,channel)]; }
T& operator()( int row, int col, int channel ) { return m_cells[makeIndex(row,col,channel)]; }
class channel_iterator
{
cube& const cube;
int const row, col;
int channel;
friend class cube;
channel_iterator( cube& all, int r, int c, int n ) : cube(all), row(r), col(c), channel(n) {}
public:
T& operator*() const { return cube(row, col, channel); }
channel_iterator& operator++() { ++channel; return *this; }
channel_iterator operator++(int) { return channel_iterator(cube, row, col, channel++); }
bool operator!=(const channel_iterator& other) const { assert(&cube == &other.cube); return (row == other.row && col == other.col && channel == other.channel); }
};
int channel_count() const { return m_cells.size() / m_nRows / m_nChannels; }
pair<channel_iterator, channel_iterator> range(int row, int col) { return make_pair(channel_iterator(*this, row, col, 0), channel_iterator(*this, row, col, channel_count())); }
};
A better pattern for implementing assignment is the copy and swap idiom.
X& X::operator= (const X& rhv)
{
X copy(rhv); //reuse copy constructor
this->swap(copy); //reuse swap method - also useful for the user of the class!
//previously held resources automatically released by the destructor of copy
}
This performs the necessary steps in an order that keeps left-hand value unchanged if an exception occurs during the copying: doesn't release resources before new resources have been successfully obtained.
And the advantage over the methods you have is that the swap method is useful not only internally for implementing the class, but also for the user of the class. In case of the CMatrix class the implementation would be:
void CMatrix<T>::swap(CMatrix<T>& other)
{
std::swap(m_pData, other.m_pData);
std::swap(m_nRows, other.m_nRows);
std::swap(m_nCols, other.m_nCols);
std::swap(m_nChannels, other.m_nChannels);
}
Also, if suitable, it is a better idea to reuse existing RAII classes instead of managing memory manually in each and every class.