0

I have created a custom vector class that uses a dynamic array to store data. The overloaded constructor takes a pointer to existing array and size of the array as the arguments.

int a[3] = { 1, 2, 3 };
Vector<int> v(a, 3);

However, when I try to change this vector using the following code, it crashes because the pointer of vector object "v" points to 0xcccccccc insted of the address of the dynamic array

v = Vector<int>(a, 3);

Why does this happen and how could I improve the assignment above?

EDIT: here is the calss code:

 template <class T> class Vector
    {
    private:
        T* mArray;
        int Length;
    public:

    Vector(){
        mArray = 0;
        Length = 0;
    };

    Vector(const Vector& rVectorData){
        Length = rVectorData.Length;
        T* pArray = new T[Length];
        for (int i = 0; i < Length; i++)
            pArray[i] = rVectorData.mArray[i];
        delete[] Array;
        mArray = pArray;
    };

    Vector(const T* aArray, int size){
        Length = size;
        T* pArray = new T[Length];
        for (int i = 0; i < Length; i++)
            pArray[i] = aArray[i];
        delete[] mArray;
        mArray = pArray;
    };

    ~Vector(){
        delete[] mArray;
        mArray = 0;
        Length = 0;
    };
}
Riko
  • 433
  • 1
  • 6
  • 20
  • 2
    An [SSCCE](http://sscce.org) would be really helpful. My immediate guess is a shallow copy of a temporary object's members and that the temporary gets cleaned up right after. – chris Jan 24 '14 at 18:47
  • does your code follow the rule of three? http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29 – Karoly Horvath Jan 24 '14 at 18:48
  • 2
    The error is on line 42. – Jerry Coffin Jan 24 '14 at 18:48
  • @JerryCoffin: the only reference I could find in Encyclopedia Galactica mentions that the code has UB. your source is clearly superior. – Karoly Horvath Jan 24 '14 at 18:52
  • @Riko Your update shows a copy constructor and destructor ... The rule of 3 states that you also need a copy-assignment operator. – Zac Howland Jan 24 '14 at 19:05
  • [0xcccccccc](https://stackoverflow.com/questions/370195/when-and-why-will-an-os-initialise-memory-to-0xcd-0xdd-etc-on-malloc-free-new) is one of the special values in MSVC debug mode. It indicates that you haven't initialized the value – phuclv Jan 25 '14 at 01:27

2 Answers2

1
delete[] mArray;
mArray = pArray;

Since this is occurring in your constructor, and you have not initialized mArray to anything (e.g. nullptr), you are attempting to delete some random area of memory (that you did not allocate), which will likely cause your program to crash (it is UB).

You can fix that by removing the delete[] mArray line as the constructor will only be called during construction.

"v" points to 0xcccccccc insted of the address of the array "a"

Since you are allocating memory in the constructor, v will not point to the address of a, as you are copying the values from a into v, which has allocated its own memory.

Additionally, since you did not define a copy-constructor, anytime you attempt to copy your vector, it will do a shallow copy. This will result in a memory corruption problem as whichever variable goes out of scope first will free the memory, leaving a dangling pointer in the other. When the latter finally goes out of scope, it will also result in UB (and likely crash your program).

As Karoly noted, when you implement your own destructor, you should follow the rule of 3.

Zac Howland
  • 15,777
  • 1
  • 26
  • 42
  • that's not even half of the story. check the rule of three. – Karoly Horvath Jan 24 '14 at 18:56
  • 1
    @KarolyHorvath That is the cause of the runtime error he is getting currently. The Rule of 3 is the answer to the next runtime error he will get. In all, there are a lot of issues with this small piece of code. – Zac Howland Jan 24 '14 at 19:01
  • @ZacHowland Addition of assignment operator solved the problem. Thanks – Riko Jan 24 '14 at 19:19
1

It seems to me that if you're going to write your own vector class (or your own semi-duplicate of almost anything that's already widely available) you should try to not only make it correct, but add something new to the mix so your code isn't just a mediocre imitation of what's already easily available (along with preferably avoiding it's being a huge step backwards in any direction either).

For example, if I were going to support initializing a Vector from an array, I'd add a template member function that deduced the size of the array automatically:

template <size_t N>
Vector(T (&array)[N]) : data(new T[N]), size(N) {
    std::copy_n(array, N, data);
}

This allows something like:

int a[]={1, 2, 3};
Vector<int> x(a);

...so you don't have to specify the size.

You've already heard about the rule of three. To avoid a step back from std::vector, you almost certainly want to update that to the rule of 5 (or else use a smarter pointer class that lets you follow the rule of zero).

The straightforward way to do that is to implement a move ctor and move assignment operator:

Vector &operator=(Vector &&src) {
    delete[] data;
    data=src.data;
    size=src.size;
    src.data=nullptr;
    src.size = 0;
    return *this;
}

Vector(Vector &&src): data(src.data), size(src.size) {
    src.data=nullptr;
    src.size=0;
}

For convenience, you also almost certainly also want to include a ctor that takes an initializer list:

Vector(std::initializer_list<T> const &i) : data(new T[i.size()]), size(i.size()) 
{
    std::copy(i.begin(), i.end(), data);
}

Finally, you just about need (or at least really want) to support an iterator interface to the contained data:

class iterator {
    T *pos;
    friend class Vector;
    iterator(T *init): pos(init) {}
public:
    iterator &operator++() { ++pos; return *this; }
    iterator &operator--() { --pos; return *this; }
    iterator &operator++(int) { iterator tmp(*this); ++pos; return tmp; }
    iterator &operator--(int) { iterator tmp(*this); --pos; return tmp; }
    T &operator*() { return *pos; }
    bool operator!=(iterator const &other) const { return pos!=other.pos; }
};

iterator begin() { return iterator(data); }
iterator end() { return iterator(data+size); }

...then you want to add const_iterator, reverse_iterator and const_reverse_iterator classes, and with them cbegin/cend, rbegin/rend and crbegin/crend to support constant and/or reversed iteration of the data.

Note, however, that most of this is just duplicating what std::vector already provides. The only new thing we've added here is the ctor that takes an array and deduces its size automatically. At the same time, that is enough to provide a fixed-size array wrapper that (other than dynamic sizing) has approximate parity with std::vector.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • It is a school assignment, of course, I know that vector class already exists, thanks for your suggestions, I have already developed some of them, however this was not the point of my question. The part I was missing was the assignment operator, but thanks for your exhaustive answer anyway. – Riko Jan 25 '14 at 15:09