Bounded Array class

P

Protoman

Is there any way I can improve this bounded array class? What other ops
should I overload? How do I use operator() to make multiple subscripts?
Here's the code:

class OutOfBounds{};

template <class T, unsigned long long Size>
class BArray
{
public:
T& operator[](const T& ix)
{
if(ix>=Size||ix<0)
throw OutOfBounds();
else
return myData[ix];
}
private:
T myData[Size];
};

Thanks!!!!
 
S

shellux

Maybe you can and some useful array operations, see begin(), end(),
rbegin(), rend(), and so on.
And nest class const_iterator and iterator are needed.

with these features you can use you BArray class with Algorithm in STL.
 
P

Protoman

shellux said:
Maybe you can and some useful array operations, see begin(), end(),
rbegin(), rend(), and so on.
And nest class const_iterator and iterator are needed.

with these features you can use you BArray class with Algorithm in STL.

Actually, I just want to use it as a standard array replacement; I'll
use std::vector when I need Algorithm. Thanks, though.
 
D

Dietmar Kuehl

Protoman said:
Is there any way I can improve this bounded array class?
class OutOfBounds{};

This is the first part I would start with: although it is not required,
exceptions being thrown, especially from library components, benefit
from deriving from 'std::exception', either directly or indirectly.
In this case, something like 'std::range_error' seems to be an
appropriate base class.
template <class T, unsigned long long Size>
class BArray
{
public:

Here a default constructor is missing which initializes the elements:

BArray(): myData() {}

Although it makes no difference for non-POD types, POD types would
go uninitialized.
T& operator[](const T& ix)

Are you sure that you want to subscript your array class with the
element type? You might want to add the flexibility to replace your
index type but I doubt that there are many occasions where the index
type happens to be identical to the element type. Obviously, you also
want to add a 'const' version of this operator.
{
if(ix>=Size||ix<0)
throw OutOfBounds();

I'd rahter throw something like

throw std::ranger_error("array index out of bound");

possibly even with the used index and the violated bound.

As noted in another article, I would also equip this class with
proper iterators: the idea behind STL is that it is extremely easy
to get support for all algorithms for a sequence. All you need are
iterators accessing the sequence which can be as simple as pointers
which could be a reasonable approach in the above case.
 
B

Ben Pope

Protoman said:
Actually, I just want to use it as a standard array replacement; I'll
use std::vector when I need Algorithm. Thanks, though.

An array doesn't preclude the use of algorithms.

Ben Pope
 
P

Protoman

OK, I modified it, but its saying, that, in the copy ctor, that there's
no field called rhs. Here's the code:
class OutOfBounds{};

template <class T, unsigned long long size>
class BArray
{
public:
BArray():myData(new T[size]){}
BArray(const BArray& rhs):rhs.myData(myData){}
~BArray(){delete[] myData;}
T& operator[](const T& ix)
{
if(ix>=size||ix<0)
throw OutOfBounds();
else
return *(myData+index);
}
private:
T* myData;
};

Any help? Thanks!!!!!!!
 
D

Dietmar Kuehl

Protoman said:
template <class T, unsigned long long size>
class BArray
{
public:
BArray():myData(new T[size]){}
BArray(const BArray& rhs):rhs.myData(myData){}

The above line shall read

BArray(const BArray& rhs): myData(rhs.myData) {}

to fix the immediate problem. However, this results in the
wrong semantics: this would copy the pointer causing the
copied array to be deleted twice. You rather need to do
something like this:

BArray(BArray const& rhs):
myData(new T[size])
{
std::copy(rhs.myData, rhs.myData + size, this->myData);
}
~BArray(){delete[] myData;}

.... and you also need to define a copy assignment:

BArray& operator= (BArray const& rhs)
{
std::copy(rhs.myData, rhs.myData + size, this->myData);
return *this;
}
T& operator[](const T& ix)
{
if(ix>=size||ix<0)
throw OutOfBounds();
else
return *(myData+index);
}
private:
T* myData;
};

Note, however, that nobody suggested that you replace the statically
sized array with a dynamically allocated one! At least I consider
this the wrong approach to a statically size array: I would go with
the embedded array.
 
P

Protoman

Dietmar said:
Protoman said:
template <class T, unsigned long long size>
class BArray
{
public:
BArray():myData(new T[size]){}
BArray(const BArray& rhs):rhs.myData(myData){}

The above line shall read

BArray(const BArray& rhs): myData(rhs.myData) {}

to fix the immediate problem. However, this results in the
wrong semantics: this would copy the pointer causing the
copied array to be deleted twice. You rather need to do
something like this:

BArray(BArray const& rhs):
myData(new T[size])
{
std::copy(rhs.myData, rhs.myData + size, this->myData);
}
~BArray(){delete[] myData;}

... and you also need to define a copy assignment:

BArray& operator= (BArray const& rhs)
{
std::copy(rhs.myData, rhs.myData + size, this->myData);
return *this;
}

Thanks!!!! Where is std::copy defined? What header?
T& operator[](const T& ix)
{
if(ix>=size||ix<0)
throw OutOfBounds();
else
return *(myData+index);
}
private:
T* myData;
};

Note, however, that nobody suggested that you replace the statically
sized array with a dynamically allocated one! At least I consider
this the wrong approach to a statically size array: I would go with
the embedded array.

What if a user created BArray<unsigned long long,10000000> array? Do
you really want God only knows how many bytes on the STACK?!!!!!? But
thanks for the advice.
 
D

Dietmar Kuehl

Protoman said:
Thanks!!!! Where is std::copy defined? What header?

Hm, seems like you successfully got me to do you homework.
Well, you need at least research which header the algorithms
are in...
What if a user created BArray<unsigned long long,10000000> array? Do
you really want God only knows how many bytes on the STACK?!!!!!?

There is no defense against blatant stupidity: Pick a sufficiently
large number of elements and the array won't fit into memory at all.
If you really want to defend against too large arrays on the stack,
you should employ some template meta programming which starts putting
the array on the heap if it has grown beyond a certain size. For
reasonably small, fixed-size arrays I would call it inappropriate to
involve memory allocation.

BTW, I just noticed that with the current implementation of the
default constructor, PODs go uninitialized. In fact, writing a
commercial strength array class with dynamic memory allocation
requires considerable more work than is currently done. Effectively,
you need to allocate plain memory, initialized it appropriately, and
release it manually because it is constructed manually.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,171
Messages
2,570,935
Members
47,472
Latest member
KarissaBor

Latest Threads

Top