0

As the title says, I try to extend the std::vector class in that way if I erase an element, the value of the position is not erased but actually set to NULL (providing a gap).

template<typename T>
class FVector : public std::vector<T> {
    typedef std::vector<T> Base;

protected:
    /** The number of elements in the vector */
    size_t elementCount;

    /**
     * The index of the last element. This field is actually vector's length. 
     * For example when you have a vector like this ["a","b","c"] then the 
     * elementCount would be 3 and lastIndex would be 2 (because indexes are 
     * zero-based). But if you erased two first elements, 
     * leaving [null, null, "c" ] then elementCount=1 (because there is only 
     * one element in the vector!) however lastIndex would still remain 2. 
     * After you erase "c" lastIndex would be set to -1 (so it's enough to 
     * add 1 to lastIndex to determine vector's length.
     */
    int lastIndex;

private:
    /**
     * Returns the index of the last not-null element in the vector, 
     * starting from position position downwards.
     *
     * @param position the position from which counting is to be begun.
     * @return last element before (or on) index <code>position</code>
     */
    int FindLastIndex(int position) {
        int nLastItem = position;

        if (position < 0) {
            return -1;
        }

        for (; nLastItem >= 0; nLastItem--) {
            if (Base::operator[](nLastItem) != NULL) {
                break;
            }
        }

        return (nLastItem);
    }

public:

    FVector(const T & value = T())
    : elementCount(0), lastIndex(-1) {
    }

    FVector(int initialCapacity, const T & value = T())
    : elementCount(0), lastIndex(-1),
      std::vector<T>(initialCapacity, value) {
    }

    size_t Capacity() const {
        return Base::size();
    }

    size_t Size() const {
        return elementCount;
    }

    int LastIndex() const {
        return lastIndex;
    }

    void AddElement(const T& obj) {
        Base::push_back(obj);

        elementCount++;
        lastIndex++;
    }

    T & ElementAt(int index) {
        if (index > lastIndex) {
            // error
        }

        return Base::at(index);
    }
    void EraseElementAt(int index) throw() {
        if (index > lastIndex) {
            std::stringstream ss;
            ss << index << " > " << lastIndex;
            throw ArrayIndexOutOfBoundsException(ss.str());
        }

        if (Base::operator[](index) != NULL) {
            elementCount--;
            T v = Base::at(index);
            delete v;
            Base::at(index) = NULL;

            if (index == lastIndex) {
                lastIndex = FindLastIndex(lastIndex - 1);
            }
        }
    }
};

It is not working like I expect. When I call the erase() method on an element the element is not set to NULL.

For example:

class Int {
    int i;
public:
     Int(int v): i(v) { };
     ~Int() { }
};

//... 

FVector<Int *> * v = new FVector<Int *>();

v->AddElement(new Int(1));
v->AddElement(new Int(3));
v->AddElement(new Int(5));
v->EraseElementAt(0);
v->EraseElementAt(2);

// ...

delete v;

will result in

[null, 3]

but I expect it to be

[null, 3, null]

Well, I do not know if that is possible what I try to achieve. I thought taking the std::vector class, which is a dynamic array (so why should I write my own array class then) give me all the basics I need to implement such thing.

Can anybody shed some light on that, I think I have some implementation issues here.

Thanks for your help!

Andreas W. Wylach
  • 723
  • 2
  • 10
  • 31
  • Just a stupid question: why would you want to implement such a thing? – Mihai Todor Jul 06 '12 at 15:34
  • I know, the idea is maybe stupid but I have something in mind I would like to try out in a project. It is also a little exercise for me. Sorry for that fuzzy answer! – Andreas W. Wylach Jul 06 '12 at 15:36
  • 5
    Consider http://stackoverflow.com/questions/4353203/thou-shalt-not-inherit-from-stdvector and the questions it links to. – Robᵩ Jul 06 '12 at 15:39
  • 2
    It's really a bad way to implement this. Try just using `boost::optional` instead of `T`. – tenfour Jul 06 '12 at 16:12
  • Yes, I will consider another way. Like said, it is / was also an excercise, so I take it as an lesson:-) Alss thanks for the link to the http://stackoverflow.com/questions/4353203/thou-shalt-not-inherit-from-stdvector. Reading that was very revealing! – Andreas W. Wylach Jul 07 '12 at 01:13

1 Answers1

3

In your EraseElementAt you have this:

        if (index == lastIndex) {
            lastIndex = FindLastIndex(lastIndex - 1);
        }

If you happen to erase the last element in the vector (which you did) it will shorten the vector (decrement lastIndex). It seems like you want your vector to not do this - rather you are wanting the vector to null but not shorten. Maybe just take this out.

emsr
  • 15,539
  • 6
  • 49
  • 62