proxy class in rvalue - how to implement assignment operator? - c++

Suppose I have a simple vector class where elements are accessed through a proxy class.
Vector class:
class vec {
public:
vec(int len) {
length = len;
data = new double [len];
}
proxy operator[](int i) {
if (i >= 0 && i < length) {
return proxy(i, data);
}
else {
std::cerr << "AHHHH!\n";
exit(1);
}
}
private:
int length;
double * data;
};
Proxy class:
class proxy {
public:
proxy(int i, double * d) {
index = i;
data = d;
}
void operator=(double rhs) {
data[index] = rhs;
}
private:
int index;
double * data;
};
How can I assign elements from the vector (or rather, from the proxy) to a variable of type double? In other words, how do I accomplish the following:
int main() {
vec a(2);
double x = 3.14;
a[0] = x; // Works!
x = a[0]; // How to make work?
return 0;
}
Unfortunately, I can't write something like:
friend double operator=(double & lhs, const proxy & p) { ... }
since operator= must be a member.

Add a conversion function to your proxy class:
class proxy
{
public:
operator double() const { return data[index]; }
// ...
};

Related

Writing a C++ iterator for a sparse matrix class

I'm attempting to get a basic constant forward-iterator to work in C++.
namespace Rcpp {
class SparseMatrix {
public:
IntegerVector i, p;
NumericVector x;
int begin_col(int j) { return p[j]; };
int end_col(int j) { return p[j + 1]; };
class iterator {
public:
int index;
iterator(SparseMatrix& g) : parent(g) {}
iterator(int ind) { index = ind; }; // ERROR!
bool operator!=(int x) const { return index != x; };
iterator operator++(int) { ++index; return (*this); };
int row() { return parent.i[index]; };
double value() { return parent.x[index]; };
private:
SparseMatrix& parent;
};
};
}
My intention is to use the iterator in contexts similar to the following:
// sum of values in column 7
Rcpp::SparseMatrix A(nrow, ncol, fill::random);
double sum = 0;
for(Rcpp::SparseMatrix::iterator it = A.begin_col(7); it != A.end_col(7); it++)
sum += it.value();
Two questions:
The compiler throws an error on the line indicated above: uninitialized reference member in 'class Rcpp::SparseMatrix&' [-fpermissive]. How can this be fixed?
How might double value() { return parent.x[index]; }; be re-worked to return a pointer to the value rather than a copy of the value?
A little context on the SparseMatrix class: like a dgCMatrix in R, this object of class SparseMatrix consists of three vectors:
i holds row pointers for every element in x
p gives indices in i which correspond to the start of each column
x contains non-zero values
Thanks to #Evg, here's the solution:
namespace Rcpp {
class SparseMatrix {
public:
IntegerVector i, p;
NumericVector x;
class iterator {
public:
int index;
iterator(SparseMatrix& g, int ind) : parent(g) { index = ind; }
bool operator!=(iterator x) const { return index != x.index; };
iterator& operator++() { ++index; return (*this); };
int row() { return parent.i[index]; };
double& value() { return parent.x[index]; };
private:
SparseMatrix& parent;
};
iterator begin_col(int j) { return iterator(*this, p[j]); };
iterator end_col(int j) { return iterator(*this, p[j + 1]); };
};
}
And it can be used as follows, for instance, to calculate colSums:
//[[Rcpp::export]]
Rcpp::NumericVector Rcpp_colSums(Rcpp::SparseMatrix& A) {
Rcpp::NumericVector sums(A.cols());
for (int i = 0; i < A.cols(); ++i)
for (Rcpp::SparseMatrix::iterator it = A.begin_col(i); it != A.end_col(i); it++)
sums(i) += it.value();
return sums;
}
And, the above function is faster than RcppArmadillo, RcppEigen, and R::Matrix equivalents when microbenchmarked from R!
Edit:
The above syntax is inspired by Armadillo. I've come to realize that a slightly different syntax (which involves fewer constructions) gives an iterator similar to Eigen:
class col_iterator {
public:
col_iterator(SparseMatrix& ptr, int col) : ptr(ptr) { indx = ptr.p[col]; max_index = ptr.p[col + 1]; }
operator bool() const { return (indx != max_index); }
col_iterator& operator++() { ++indx; return *this; }
const double& value() const { return ptr.x[indx]; }
int row() const { return ptr.i[indx]; }
private:
SparseMatrix& ptr;
int indx, max_index;
};
Which can then be used like this:
int col = 0;
for (Rcpp::SparseMatrix::col_iterator it(A, col); it; ++it)
Rprintf("row: %3d, value: %10.2e", it.row(), it.value());

Writing an accessor method for inherited class with sparse member data?

Say I have a simple vector class, vec:
#include <iostream>
#include <stdlib.h>
class vec {
public:
vec() {}
// Constructor.
vec(int n) {
len = n;
data = new double[len];
}
// Destructor.
~vec() { delete [] data; }
// Accessor.
double & operator[](int i) const {
check_index(i);
return data[i];
}
// Other methods...
// ....
protected:
int len;
double * data;
void check_index(int i) const {
if(i < 0 || i >= len) {
std::cerr << "Bad access.\n";
exit(1);
}
}
};
Now suppose I have a special type of vector with sparse structure, e.g., where every even-index is zero. Call this oddvec. Instances of oddvec should be declared just as with the vec class, but underneath, the memory use should be efficient since only half the data is non-zero.
The accessor for the oddvec class should return 0 if the index is even, and return the odd-index element (stored sequentially) otherwise. There a couple problems with this:
The double & return type is violated if the index is even, since the constant value, 0, is returned.
It's not clear to me how to handle the situation when an even index element is used as an lvalue. E.g., v[0] = 3.0 should not be allowed in the oddvec class, but is perfectly acceptable in the vector class. We can't simply throw an error when even indexes are used, because even indexes are fine as long as the intention is as an rvalue.
How do I design the accessor function for the oddvec class, while both keeping the memory storage efficient and inheriting all the methods from the parent?
Non-working example of oddvec:
class oddvec : public vec {
public:
// Constructor.
oddvec(int n) {
len = n;
data = new double[len/2];
}
// Accessor (doesn't work!)
double & operator[](int i) const {
check_index(i);
if (i%2 == 0)
return 0;
else
return data[(i-1)/2];
}
};
Upon compilation:
main.cpp: In member function ‘double& oddvec::operator[](int) const’:
main.cpp:49:20: error: invalid initialization of non-const reference of type ‘double&’ from an rvalue of type ‘double’
return 0;
Working example using proxy classes:
I have implemented a proxy class as suggested in the answer below.
proxies.h
#ifndef PROXIES_H
#define PROXIES_H
#include <iostream>
#include <stdlib.h>
class proxy {
public:
proxy(int i, double v, double * d) {
index = i;
value = v;
data = d;
}
void operator=(double rhs) {
data[index] = rhs;
}
friend std::ostream & operator<<(std::ostream & outs, const proxy & p) {
outs << p.value;
return outs;
}
protected:
int index;
double value;
double * data;
};
class oddproxy : public proxy {
public:
oddproxy(int i, int v, double * d) : proxy(i, v, d) {}
void operator=(double rhs) {
if (index%2 == 0) {
std::cerr << "Even entries of oddvec are not assignable.\n";
exit(1);
}
data[index/2] = rhs;
}
};
#endif
vectors.h
#ifndef VECTORS_H
#define VECTORS_H
#include "proxies.h"
class vec {
public:
vec() {}
// Constructor.
vec(int n) {
len = n;
data = new double[len];
}
// Destructor.
~vec() { delete [] data; }
// Accessor.
proxy operator[](int i) const {
check_index(i);
return proxy(i, data[i], data);
}
inline int length() const { return len; }
// Other methods...
// ....
protected:
int len;
double * data;
void check_index(int i) const {
if(i < 0 || i >= len) {
std::cerr << "Bad access.\n";
exit(1);
}
}
};
class oddvec : public vec {
public:
// Constructor.
oddvec(int n) {
len = n;
data = new double[len/2];
}
// Accessor.
oddproxy operator[](int i) const {
check_index(i);
return oddproxy(i, (i%2 == 0) ? 0 : data[i/2], data);
}
};
#endif
main.cpp
#include <iostream>
#include "vectors.h"
int main () {
int N = 5;
vec V(N);
oddvec O(N);
for(int i=0; i < V.length(); i++) {
V[i] = i;
if(i%2 != 0) {
O[i] = i;
}
}
for(int i=0; i < O.length(); i++) {
std::cout << "V[" << i << "]=" << V[i] << ", "
<< "O[" << i << "]=" << O[i] << "\n";
}
O[0] = 13;
return 0;
}
output
V[0]=0, O[0]=0
V[1]=1, O[1]=1
V[2]=2, O[2]=0
V[3]=3, O[3]=3
V[4]=4, O[4]=0
Even entries of oddvec are not assignable.
You can use proxy object to do this.
simple sample code:
#include <iostream>
#include <vector>
using namespace std;
class very_odd_vector{
public:
class only_odd_proxy;
friend class only_odd_proxy;
only_odd_proxy operator [](int index);
int operator [](int index)const{return index%2==0?0:content[index/2];}
unsigned int size()const{return content.size()*2;}
private:
vector<int> content{1,3,5,7,9};
};
class very_odd_vector::only_odd_proxy{
public:
only_odd_proxy(very_odd_vector& vec,int index):vec(vec),index(index){}
operator int(){return index%2==0 ? 0 : vec.content[index/2];}
only_odd_proxy& operator =(int value){
if(index%2==0)
cout << "BAD OPERATION";//any error you want
else
vec.content[index/2] = value;
return *this;
}
private:
very_odd_vector& vec;
int index;
};
auto very_odd_vector::operator [](int index)->only_odd_proxy{return only_odd_proxy(*this,index);}
int main(){
very_odd_vector v;
cout << "reading value\n";
for(int i=0;i<v.size();++i)
cout << v[i] <<'\n';
cout << "writting value\n";
for(int i=0;i<v.size();++i){
cout << i << ':';
v[i]=10;
cout << '\n';
}
cout << "reading value\n";
for(int i=0;i<v.size();++i)
cout << v[i] <<'\n';
}
Edit for updated part of question :
I think this class will fit your need more.
//Both base and inherit class return this class
class maybe_readonly_proxy {
public:
maybe_readonly_proxy(double* data, bool readonly):readonly(readonly),data(data){}
maybe_readonly_proxy& operator=(double rhs) {
if(readonly){/*whatever error*/}
else {*data = rhs;}
return *this;
}
operator double()const{return *data;}
private:
bool readonly;
double * data;
};
You may need a variable to contain readonly (0 in this case) value, or modify the operator double() the check readonly state
Or just implement get and set method separately and do not use this proxy may be another choice.

Efficent Sum and Assignment operator overloading in C++

Hi I'm implementing a matrix class in c++
I know that there are great libraries that do that like opencv but I need to do that myself.
For example if I implement the sum I can do like this
class Mat{
public:
double* data;
int rows,cols;
Mat(int r,int c):rows(r),cols(c){
data = new double[r*c];
}
};
void Sum(Mat& A,Mat& B,Mat& C){
for (int i = 0; i < A.rows*A.cols; ++i){
C.data[i] = A.data[i]+B.data[i];
}
}
int main(){
//Allocate Matrices
Mat A(300,300);
Mat B(300,300);
Mat C(300,300);
//do the sum
sum(A,B,C);
}
I would like to get something more readable like this but without losing efficiency
C = A + B
This way C is reallocated every time and I don't want that
Thank you for your time
Delay the calculation.
class MatAccess {
friend class Mat;
friend class MatOpAdd;
virtual double operator[](int index) const = 0;
};
class MatOpAdd: public MatAccess {
friend class Mat;
private:
const MatAccess& left;
const MatAccess& right;
MatOpAdd(const MatAccess& left, const MatAccess& right):
left(left), right(right) {}
double operator[](int index) const {
return left[index] + right[index];
}
};
class Mat: public MatAccess{
public:
double* data;
int rows,cols;
Mat(int r,int c):rows(r),cols(c){
data = new double[r*c];
}
MatOpAdd operator +(const MatAccess& other) {
return MatOpAdd(*this, other);
}
const Mat& operator = (const MatAccess& other) {
for(int i = 0; i < rows*cols; ++i) {
data[i] = other[i];
}
return *this;
}
private:
double operator[](int index) const {
return data[index];
}
double& operator[](int index) {
return data[index];
}
};
int main(){
//Allocate Matrices
Mat A(300,300);
Mat B(300,300);
Mat C(300,300);
//do the sum
C = A + B;
}
Now the '+' calculation will be done in the "operator="
Things I would change:
MatAccess should include the dimensions (rows,cols).
Mat adding constructors and operator= or make it not copyable
Mat::operator+ and Mat::operator= check for equal rows,col
delete memory when not used anymore or
use std::vector for simpler memory managment.
Created a bigger example here: https://gist.github.com/KoKuToru/1d23af4bbf0b2bc89893

Assign value using overloaded subscript operator

I am trying to create custom array indexed from 1 using subscript operator. Getting value works fine, but I have no clue, why assign using subscript operator doesn't work.
class CEntry {
public:
CKey key;
CValue val;
CEntry(const CKey& key, const CValue& val) {
this->key = key;
this->val = val;
}
CEntry& operator= (const CEntry& b) {
*this = b;
return *this;
};
};
...
class EntriesArray {
public:
CEntry **entries;
int length;
EntriesArray(int length) {
this->length = length;
entries = new CEntry*[length];
int i;
for (i = 0; i < length + 1; i++) {
entries[i] = NULL;
}
};
CEntry& operator[] (const int index) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
return *entries[index - 1];
};
};
Constructs array this way
EntriesArray a(5);
This works
a.entries[0] = new CEntry(CKey(1), CValue(1));
cout << a[1].val.value << endl;
This doesn't work
a[1] = new CEntry(CKey(1), CValue(1));
EDIT:
Using
CEntry *operator=( CEntry *orig)
it compiles okey, but gdb stops at
No memory available to program now: unsafe to call malloc warning: Unable to restore previously selected frame
with backtrace
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00007fff5f3ffff8
0x00000001000013c8 in CEntry::operator= (this=0x0, orig=0x1001008d0) at /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp:20
20 /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp: No such file or directory.
in /Users/seal/Desktop/efa du2_pokus2/efa du2_pokus2/main.cpp
At first... This:
CEntry& operator= (const CEntry& b) {
*this = b;
return *this;
};
Shouldn't work (this should result in recursive call of operator=).
The second thing is that you're trying to assign CEntry * to CEntry, this would work if you had CEntry *operator=( CEntry *orig), but I think this is bad coding practice.
This question may be related to this one.
I tried to fix your code; I believe that this is what you were trying to do:
(tested this code on g++ 5.3.0)
#include <iostream>
#include <stdexcept>
#include <string>
// Some implementation for CKey and CValue:
typedef int CKey;
struct CValue {
int value;
CValue(int value=0) : value(value) {}
};
class CEntry {
public:
CKey key;
CValue val;
CEntry(): key(0), val(0) {}
CEntry(const CKey& key, const CValue& val): key(key), val(val) {}
CEntry& operator= (const CEntry& b) {
this->key = b.key;
this->val = b.val;
return *this;
};
};
class EntriesArray {
public:
CEntry *entries;
int length;
EntriesArray(int length) {
this->length = length;
entries = new CEntry[length];
};
CEntry& operator[] (const int index) {
if (index < 1 || index > length) {
throw std::domain_error("out of bounds!");
}
return entries[index - 1];
};
};
int main(int argc, char* argv[]) {
using namespace std;
EntriesArray a(5);
// This works
a.entries[0] = CEntry(CKey(1), CValue(1));
cout << a[1].val.value << endl;
// This doesn't work
a[1] = CEntry(CKey(2), CValue(2));
cout << a[1].val.value << endl;
}
Also you might want to use a[1] as a[1].val.value e.g.:
cout << a[1] << endl;
To do this just add to this line to cEntry:
operator int() { return val.value; }
I hope it helps.
You could try replacing
CEntry& operator[] (const int index) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
return *entries[index - 1];
};
with
void Add(const int index, CEntry *pEntry) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
entries[index - 1] = pEntry;
};
but since you are now storing references to objects allocated on the heap (with new) you will need a destructor ~EntriesArray() to delete them all.
Because EntriesArray::operator[] returns a CEntry &, but new CEntry returns a CEntry *.
Perhaps you want a[1] = CEntry(CKey(1), CValue(1))? (no new.)
By the way, your current definition of CEntry::operator= will lead to a stack overflow.
This
return *entries[index - 1];
dereferences a NULL pointer.
You want the pointer itself to be overwritten by a[1] = new CEntry(CKey(1), CValue(1));, not the pointed-to-value.
Try this:
class EntriesArray
{
public:
int length;
CEntry **entries;
EntriesArray( int length ) : length(length), entries(new CEntry*[length]())
{
}
// defaulted special member functions are inappropriate for this class
EntriesArray( const EntriesArray& ); // need custom copy-constructor
~EntriesArray(); // need custom destructor
EntriesArray& operator=(const EntriesArray&); // need custom assignment-operator
CEntry*& operator[] (const int index) {
if (index < 1 || index > length) {
throw ArrayOutOfBounds();
}
return entries[index - 1];
}
};
Further to my comment above:
To make it work with writing new values, you probably need something like this
(I haven't double checked for off by one or ptr vs reference stuff)
CEntry& operator[] (const int index) {
if (index < 1) {
throw ArrayOutOfBounds();
}
// Add default elements between the current end of the list and the
// non existent entry we just selected.
//
for(int i = length; i < index; i++)
{
// BUG is here.
// We don't actually know how "entries" was allocated, so we can't
// assume we can just add to it.
// We'd need to try to resize entries before coming into this loop.
// (anyone remember realloc()? ;-)
entries[i] = new CEntry();
}
return *entries[index - 1];
};

Template, inheritance and operators

I have some trouble with class template inheritance and operators (operator +),
please have a look at these lines:
Base vector class (TVector.h):
template<class Real, int Size>
class TVector {
protected:
Real* values;
public:
...
virtual TVector<Real, Size>& operator=(const TVector<Real, Size>& rTVector) { //WORKS
int i = 0;
while (i<Size) {
*(values+i) = *(rTVector.values+i);
i++;
}
return *this;
}
virtual TVector<Real, Size> operator+(const TVector<Real, Size>& rTVector) const {
int i = 0;
Real* mem = (Real*)malloc(sizeof(Real)*Size);
memcpy(mem, values, Size);
while (i<Size) {
*(mem+i) += *(rTVector.values+i);
i++;
}
TVector<Real, Size> result = TVector<Real, Size>(mem);
free(mem);
return result;
}
};
2D vector class (TVector2.h):
template<class Real>
class TVector2: public TVector<Real, 2> {
public:
...
TVector2& operator=(const TVector2<Real>& rTVector) { //WORKS
return (TVector2&)(TVector<Real, 2>::operator=(rTVector));
}
TVector2 operator+(TVector2<Real>& rTVector) const { //ERROR
return (TVector2<Real>)(TVector<Real, 2>::operator+(rTVector));
}
};
Test (main.cpp):
int main(int argc, char** argv) {
TVector2<int> v = TVector2<int>();
v[0]=0;
v[1]=1;
TVector2<int> v1 = TVector2<int>();
v1.X() = 10;
v1.Y() = 15;
v = v + v1; //ERROR ON + OPERATOR
return 0;
}
Compilation error (VS2010):
Error 2 error C2440: 'cast de type' : cannot convert from
'TVector<Real,Size>' to 'TVector2' ...
What is wrong here ? is there a way to do this kind of stuff ?
Just looking for a way to not redefine all my Vectors classes.
I keep searching to do it, but I will be glad to get some help from you guys.
Sorry for bad English,
Best regards.
#include <memory>
using namespace std;
template<class Real, int Size> class TVector {
protected:
Real *_values;
public:
TVector() {
// allocate buffer
_values = new Real[Size];
}
TVector(Real *prValues) {
// check first
if (prValues == 0)
throw std::exception("prValues is null");
// allocate buffer
_values = new Real[Size];
// initialize buffer with values
for (unsigned int i(0U) ; i < Size ; ++i)
_values[i] = prValues[i];
}
// Do not forget copy ctor
TVector(TVector<Real, Size> const &rTVector) {
// allocate buffer
_values = new Real[Size];
// initialize with other vector
*this = rTVector;
}
virtual ~TVector() {
delete [] _values;
}
virtual Real &operator[](int iIndex) {
// check for requested index
if (iIndex < 0 || iIndex >= Size)
throw std::exception("requested index is out of bounds");
// index is correct. Return value
return *(_values+iIndex);
}
virtual TVector<Real, Size> &operator=(TVector<Real, Size> const &rTVector) {
// just copying values
for (unsigned int i(0U) ; i < Size ; ++i)
_values[i] = rTVector._values[i];
return *this;
}
virtual TVector<Real, Size> &operator+=(TVector<Real, Size> const &rTVector) {
for (unsigned int i(0U) ; i < Size ; ++i)
_values[i] += rTVector._values[i];
return *this;
}
virtual TVector<Real, Size> operator+(TVector<Real, Size> const &rTVector) {
TVector<Real, Size> tempVector(this->_values);
tempVector += rTVector;
return tempVector;
}
};
template<class Real> class TVector2: public TVector<Real, 2> {
public:
TVector2() {};
TVector2(Real *prValues): TVector(prValues) {}
TVector2 &operator=(TVector2<Real> const &rTVector) {
return static_cast<TVector2 &>(TVector<Real, 2>::operator=(rTVector));
}
TVector2 &operator+=(TVector2<Real> const &rTVector) {
return static_cast<TVector2 &>(TVector<Real, 2>::operator+=(rTVector));
}
TVector2 operator+(TVector2<Real> const &rTVector) {
return static_cast<TVector2 &>(TVector<Real, 2>::operator+(rTVector));
}
Real &X() { return _values[0]; }
Real &Y() { return _values[1]; }
};
int main(int argc, char** argv) {
TVector2<int> v = TVector2<int>();
v[0]=0;
v[1]=1;
TVector2<int> v1 = TVector2<int>();
v1.X() = 10;
v1.Y() = 15;
v = v1;
v += v1;
v = v + v1;
return 0;
}
Some misc notes:
it's very bad that you use malloc against of new. Real can be POD only to allow vector work well in your case. Use new or provide custom creation policy if you think that malloc provides better performance on PODs. Also do not forget to use delete [] instead of free while destroying memory buffer.
It's better to perform bounds checking while overloading operator[]
for better performance use ++i instead of postfix form. In former no temporary value is created.