This is a suggestion I have thrown together quickly and not thoroughly tested but it seems to work:
#include <iostream>#include <vector>using namespace std;class Matrix{private:class Imp{public: Imp(int w,int h) : r(0),wt(w),ht(h) { v.resize(w*h); cout << "imp\n"; } ~Imp(){ cout << "free\n"; } vector<float> v; int r,wt,ht;};class MFloat{public: MFloat(Matrix *M,float *v,int fx,int fy) : Mp(M),Fv(v),x(fx),y(fy) { } operator float() const { return *Fv; } operator float&() { if(Mp->Im->r>1) Mp->GetOwnCopy(); Fv=&(Mp->Im->v[(y*Mp->Im->wt)+x]); return *Fv; } Matrix *Mp; float *Fv; int x,y;}; Imp *Im; friend class MFloat; void GetOwnCopy();public: Matrix(int w,int h){ Im=new Imp(w,h); Im->r=1; } Matrix(const Matrix &M){ Im=M.Im; ++Im->r; } ~Matrix(){ --(Im->r); if(Im->r==0) delete Im; } const Matrix &operator=(const Matrix &M) { --Im->r; if(Im->r==0) delete Im; Im=M.Im; ++Im->r; return *this; } float operator()(int x,int y) const { return Im->v[(y*Im->wt)+x]; } MFloat operator()(int x,int y) { return MFloat(this,&(Im->v[(y*Im->wt)+x]),x,y); }};void Matrix::GetOwnCopy(){ Imp *I=Im; Im=new Imp(I->wt,I->ht); Im->v=I->v; Im->r=1; --(I->r); if(I->r==0) delete I;}int main(){ Matrix M(5,5),N=M; M(2,2)=23.0f; cout << M(2,2) << endl;}
It relys on the fact that when a non-const Matrix has its () operator called, it returns the MFloat class, which is private to Matrix. MFloat has operator float and operator float& functions and it would
appear that the correct one gets called depending on whether you are asking for an lvalue or not.
In the int main() as above, the GetOwnCopy is called before the assignment. If you take the M(2,2)=23.0f line out, it isn't called since the operator float is used to get the value for the cout statement rather than the operator float&.
I have no idea whether this would work if developed or not, or whether there is a well-defined precedence for calling the non-reference operator float function over the reference version depending on if an lvalue is being used or not, so I make no apology if this program is relying on undefined behaviour or non-standard aspects of the compiler I tested this on. It is just an idea that I hope might provoke some discussion.