views:

174

answers:

4

Do any of the popular C++ libraries have a class (or classes) that allow the developer to use arrays with arbitrary indices without sacrificing speed ?

To give this question more concrete form, I would like the possibility to write code similar to the below:

//An array with indices in [-5,6)
ArbitraryIndicesArray<int> a = ArbitraryIndicesArray<int>(-5,6);  
for(int index = -5;index < 6;++index)
{
    a[index] = index;
}

Thanks...

+2  A: 

Use the map class from the STL:

std::map<int, int> a;
for( int index = -5; index < 6; ++index )
{ 
    a[index] = index; 
}

map is implemented internally as a sorted container, which uses a binary search to locate items.

Jon Benedicto
The O(log n) lookup time is slower than the O(1) of arrays though
Yacoby
The alternative is std::tr1::unsorted_map that is the current standard implementation of a hash map, so it's most of the time O(1)
Klaim
This wouldn't do the job. I need O(1) all the time.
Bartłomiej Siwek
+4  A: 

A std::vector<int> would do the trick here.
Random acess to a single element in a vector is only O(1).

If you really need the custom indices you can make your own small class based on a vector to apply an ofset.

f4
+5  A: 

Really you should be using a vector with an offset. Or even an array with an offset. The extra addition or subtraction isn't going to make any difference to the speed of execution of the program.

If you want something with the exact same speed as a default C array, you can apply the offset to the array pointer:

int* a = new int[10];
a = a + 5;
a[-1] = 1;

However, it is not recommended. If you really want to do that you should create a wrapper class with inline functions that hides the horrible code. You maintain the speed of the C code but end up with the ability to add more error checking.

As mentioned in the comments, after altering the array pointer, you cannot then delete using that pointer. You must reset it to the actual start of the array. The alternative is you always keep the pointer to the start but work with another modified pointer.

//resetting the array by adding the offset (of -5)
delete [] (a - 5);
Yacoby
You've also created a memory leak.
David Thornley
Would there be a problem using -1? as array subscripts are really unsigned under the hood?
EvilTeach
@David not really, you just reverse the operation performed to get the offseted array when you want to delete the pointer.
Yacoby
@EvilTeach Microsoft say they are supported. http://msdn.microsoft.com/en-us/library/59682zc4(VS.80).aspx
Yacoby
@yacoby yep. thanks nice link. This is the only correct answer to the question.
EvilTeach
This is dirty but will do the trick. Thanks.
Bartłomiej Siwek
A: 

Answer edited because I'm not very smart.

Wrap an std::vector and an offset into a class and provide an operator[]:

template <class T>
class ArbVector
{
    private:
        int _offset;
        std::vector<T> container;
    public:
        ArbVector(int offset) : _offset(offset) {}
        T& operator[](int n) { return container[n + _offset] }
};

Not sure if this compiles, but you get the idea.

Do NOT derive from std::vector though, see comments.

suszterpatt
You should never derive from the STL container classes, since they all lack a virtual destructor.
Sean
No, no, no, never subclass an STL object. None of their methods are virtual and you will have problems down the road. Encapsulate the std::vector in your own class an passthru to the underlying vector most of the functions.
jmucchiello
std::vector's d-tor isn't defined as virtual, so it's not a good idea to inherit from it.
luke
I will admit, I wasn't aware of this... but what could go wrong in this specific case?
suszterpatt
private inheritance would be OK though
Manuel