Hi guys,
I'm sure that the answer to this is simple, but I don't know what it is and it's bugging me.
For reasons that aren't important, I'm trying to make a kind of light-ish weight array class. I want to be able to use syntax like that of std::vector
for the at()
method:
std::vector v(10,1);
std::cout << v.at(3) << std::endl; /* uses const_reference at(size_type __n) const */
v.at(3) = 3; /* uses reference at(size_type __n) */
So, I've tried to implement my own version of this in a simple Array
class:
#include <stdexcept>
#include <iostream>
template< typename __T >
class Array{
public :
typedef const __T& const_reference;
typedef __T& reference;
/* some constructors */
Array(){
is_initialised__ = false;
shallow_copy__ = false;
Sz__ = 0;
}
Array(unsigned new_size){
try{ Data__ = new __T[new_size]; }
catch(std::exception &e){ throw std::exception(e); }
is_initialised__ = true;
shallow_copy__ = false;
Sz__ = new_size;
}
Array(const Array< __T > &original){
Sz__ = original.size();
is_initialised__ = !original.is_null();
Data__ = original.Data__;
shallow_copy__ = true;
}
/* Destructor */
~Array(){
if(is_initialised__ && (shallow_copy__ == false)) delete[] Data__;
}
/* Unsafe access operator */
reference operator[](const unsigned n_){
if(shallow_copy__) /* Make a deep copy */
pv_deep_copy__();
return *(this->Data__ + n_);
}
const_reference operator[](const unsigned n_) const{
return *(this->Data__ + n_);
}
/* Safe access operator */
reference at(const unsigned n_){
std::cout << "reference " << n_ << ": "; // some debugging text
if(i < Sz__ && is_initialised__){
if(shallow_copy__) /* Make a deep copy */
pv_deep_copy__();
return (*this)[n_];
}
else throw std::exception();
}
const_reference at(const unsigned n_) const{
std::cout << "const_reference " << n_ << ": "; // some debugging text
if(i < Sz__ && is_initialised__) return (*this)[n_];
else throw std::exception();
}
/* Clear the array */
void clear(){
if(is_initialised__){
if(shallow_copy__) Data__ = NULL;
else delete[] Data__;
is_initialised__ = false;
Sz__ = 0;
}
}
/* Check some status-type things */
unsigned size() const{ return Sz__; }
bool is_null() const{ return !is_initialised__; }
private :
__T *Data__;
unsigned Sz__;
bool is_initialised__;
bool shallow_copy__;
/* Perform a deep-copy of the data */
void pv_deep_copy__(){
std::cerr << "(Making deep copy) "; // Some debugging text
__T * const Dt__ = Data__;
try{ Data__ = new __T[Sz__]; }
catch(std::exception &e){ throw std::exception(); }
for(unsigned i = 0; i < Sz__; ++i)
*(Data__ + i) = *(Dt__ + i);
shallow_copy__ = false;
}
};
So, if I then write something that uses this class:
#include "test_arraytemplate.h"
int main(){
/* Make an Array */
Array< int > a(10, 2);
/* Make another array using the copy ctor */
Array< int > b(a);
/* Should use reference at() */
a.at(1) = 3;
/* Should use reference at() for 'a' and const_reference at() const for 'b' */
a.at(1) = b.at(1);
return 0;
}
However, const_reference at() const
never gets called. Can anyone see why this is? As far as I can see, my version and the std::vector
version have pretty much identical signatures, so why does it work from the STL, but not for me? I need to be able to make the distinction because I want to try and use a shallow copy type system, so when the copy c'tor is invoked it doesn't copy the actual data, and it won't as long as const
methods are used. When a method tries to change the data a deep copy is taken. However, this problem is screwing that up :o(