Hello,
I hope this is the right place for my question (if not, I would appreciate any suggestions where to direct the question)
Below is a working C++ program involving a class template and [] operator overloading. The program has been tested with the g++ compiler on Ubuntu 12.10 as well as with the Visual Studio 2012 on Windows. Hopefully, the program is adequately explained in its comments. I cannot understand why the proposed change in the program does not work. The program has been examined by several people, and nobody up to now has been able to come up with an answer why the change / improvement proposed in the comment at the end of the program does not work.
Regards,
bostjanv
PROGRAM
#include <stdlib.h>
#include <stdarg.h>
#include <iostream>
#include <cassert>
// Array is a class template for a multidimensional array structure
// (justification: for example, in C++ one can't make a definition
// "<type> *a[][][];"). It is used in the following way (int is used
// as an example type):
//
// Array<int> a(<ptr to space occupied by array>,n,d_0,d_1,...,d_{n-1});
// (see specific example of array a, which is defined in front of
// the function main)
//
// apart from its constructor the class has the following members:
// array, not relevant here
// len, not relevant here
// operator[], overloads the [] operator
// v, extracts an array component
// r, returns a reference to an array component
short indexnbr=0;
template <typename T> class Array {
short /*indexnbr,*/dims; // for meaning see comment in front of Array
int *c,indexval; // ibid.
T* a; // ibid.
public:
// ar is pointer to beginning of array; assigned to a
// constructor; n is nbr. dimensions; ... are sizes of dimensions,
// d_0,d_1,...,d_{n-1}; n is assigned to dims
// c:subarray dimensions (d_1*d_2*...*d_{n-1},d_2*..*d_{n-1},...,d_{n-1})
// indexval used to access elements; if x_0,x_1,...,x_{n-1} are the
// individual indices, in order, then
// indexval=\sum^{n-2}_{i=0}(x_i*c_{i+1})+x_{n-1}
Array(T* ar,int n,...) {
va_list argptr;
int i;
c=(int*)malloc(n*sizeof(int));
va_start(argptr,n);
for (i=0;i<n;i++) {
c[i]=va_arg(argptr,int);
}
va_end(argptr);
for (i=n-2;i>=0;i--) {c[i]=c[i]*c[i+1];}
a=ar;
/*indexnbr=0;*/dims=n;
}
// return reference to whole array
T* array() { return a; }
// length (size) of one-dimensional array
int len() {
assert(dims==1);
return c[0];
}
// length (size) of dimension i in multi-dimensional array
int len(int i) {
assert(i<=dims);
if (i==dims){return c[i-1];}
else {return c[i-1]/c[i];}
}
// overloaded [] operator; when indices are x_0,x_1,...,x_{dims-1}
// indexval=x_0*c[1]+..+x_{n-2}*c[dims-1]+x_{dims-1}
Array operator[](int x) {
assert(indexnbr<dims);
if (indexnbr==0) {indexval=0;}
indexnbr++;
if (indexnbr==dims) { indexval+=x;}
else {indexval+=x*c[indexnbr];}
return *this;
}
// return a[indexval]
T v () {
assert(indexnbr==dims);
indexnbr=0;
return *(T*)(a+indexval);
}
// return ref. to a[indexval]
T& r () {
T& refa=*(T*)(a+indexval);
assert(indexnbr==dims);
indexnbr=0;
return refa;
}
};
for (j=0; j<=2; j++) { // a_sp is initialized to
a[0][0][j].r()=j+1; // {1,2,3,10,20,30,100,200,300,1000,2000,3000}
}
for (j=0; j<=2; j++) {
a[0][1][j].r()=(j+1)*10;
}
for (j=0; j<=2; j++) {
a[1][0][j].r()=(j+1)*100;
}
for (j=0; j<=2; j++) {
a[1][1][j].r()=(j+1)*1000;
}
for (i=0; i<=1; i++) { // we print a list of index 3-tuples
for (j=0; j<=1; j++) { // together with the corresponding components
for (k=0; k<=2; k++) {
std::cout << "i=" << i << "; j=" << j << "; k=" << k << "; a[i,j,k]=";
std::cout << a[i][j][k].v() << std::endl;
}
}
}
}
// program was tested on Ubuntu Linux 12.10; g++ version 4.7.2
//
// output of the program is
//
// i=0; j=0; k=0; a[i,j]=1
// i=0; j=0; k=1; a[i,j]=2
// i=0; j=0; k=2; a[i,j]=3
// i=0; j=1; k=0; a[i,j]=10
// i=0; j=1; k=1; a[i,j]=20
// i=0; j=1; k=2; a[i,j]=30
// i=1; j=0; k=0; a[i,j]=100
// i=1; j=0; k=1; a[i,j]=200
// i=1; j=0; k=2; a[i,j]=300
// i=1; j=1; k=0; a[i,j]=1000
// i=1; j=1; k=1; a[i,j]=2000
// i=1; j=1; k=2; a[i,j]=3000
//
// Now the PROBLEM:
//
// global variable indexnbr is not a good solution (multithread or
// multiprocess situation). It would be much better to make it into a
// member of the Array class. This is achieved by
//
// -- commenting out global indexnbr
// -- uncommenting indexnbr within the Array template
// -- uncommenting indexnbr initialization within the Array constructor
//
// However, after this is done the template class Array does not work.
// In the example illustrated by the main function when a debugger is
// used it is discovered that even though indexnbr is set to zero within
// the r or v function, the value of indexnbr is 1 on exit from r or v.
// Consequently, the assert on line 65 above will throw an exception.
// I do not understand why the effect of the statements on lines 75 and
// 82 are lost.
The class requires a user defined copy constructor. Also, destructor and copy assignment operator.
As a temporary kludge (which would do nothing more than enable you to run this program with no apparent errors), change Array operator[](int x) { to Array& operator[](int x) {
Hello,
Thanks a lot for your advice. Your "temporary kludge" does work. However, since I am not that experienced in C++ I wonder whether you can elaborate somewhat on "user defined copy constructor" and "copy assignment operator" (or give me some reference).
Regards,
bostjanv