0

I am completely new to C++ and wanted to try and make a simple generic(not sure if this is proper terminology) array class which would essentially work as arrays in java(mainly for the handy length field). Here is all the code:

#include <iostream>


template <typename T>
class Array
{
private:
    T* ar;
public:
    const unsigned int length;

    Array(unsigned int length_) : length(length_), ar(new T[length]) {}
    void insert(unsigned int, T);
    T& get(unsigned int);
    T& operator[](unsigned int);
};

template <typename T> void Array<T>::insert(unsigned int index, T dataToAdd)
{
    if(index>=length)
        {throw -1;}
    ar[index]=dataToAdd;
}

template <typename T> T& Array<T>::get(unsigned int index)
{
    if(index>=length)
        {throw -1;}
    return ar[index];
}

template <typename T> T& Array<T>::operator[](unsigned int index)
    {return this->get(index);}


int main()
{
    std::cout << "main start\n";

    Array<int> nums1=Array<int>(2);
    nums1[0]=4;
    nums1[1]=10;
    std::cout << "length of nums1:" << nums1.length << "\n";    

    Array<int> nums2=Array<int>(2);
    nums2[0]=8;
    nums2[1]=5;
    std::cout << "length of nums2:" << nums2.length << "\n";

    Array<int> nums3=Array<int>(2);
    std::cout << "nums3 created\n";
    nums2[0]=3;
    std::cout << "added to index 0\n";
    nums2[1]=15;
    std::cout << "added to index 1\n";
    std::cout << "length of nums3:" << nums3.length <<"\n";

    std::cout << "main end\n";
}

It compiles just fine(using MinGW) but when I run it I get the following output:

main start
length of nums1:2
length of nums2:2
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

Since the last thing being printed by cout is length of nums2:2 I assume the exception is thrown on the line after: Array<int> nums3=Array<int>(2);

What is the reason for this? I can't be out of memory can I?

EFTH
  • 475
  • 5
  • 14
  • Changing the constructor this way worked for me: `Array(unsigned int length_) : length(length_), ar(new T[length_]) {}` – dragosht Jun 13 '14 at 09:29
  • 1
    Since you're new: Please *never* use the words "just fine", or "works perfectly". If those words applied, you wouldn't need to post. – Kerrek SB Jun 13 '14 at 09:30
  • I guess you need to learn about the standard library and discover that this class will not be useful to you. Apart from as a means to learn about the language. – David Heffernan Jun 13 '14 at 09:31
  • It worked for me as well, thank you! But, why did it work? – EFTH Jun 13 '14 at 09:31
  • In addition to the answer, remember that in C++ you should free the memory allocated with `new`. So, your class needs a destructor such as `~Array() { delete[] ar; }` – anumi Jun 13 '14 at 09:36
  • @DavidHeffernan I do know that vector exists, this is purely to learn about the language. – EFTH Jun 13 '14 at 09:37
  • If you would enable warnings for your compiler you'd also get some message about this initialization ordering. Something like this `warning: Array::length will be initialized after [-Wreorder]` – dragosht Jun 13 '14 at 09:38
  • [This is the closest possible duplicate](http://stackoverflow.com/a/8854435/1322972) I can quickly find. Lightness even goes the extra mile to cite the standard. – WhozCraig Jun 13 '14 at 09:42

1 Answers1

3

Regardless of order on your initialization line, member variables are initialized in the order they are declared in the class. Thus this:

private:
    T* ar;
public:
    const unsigned int length;

means ar will be initialized before length, so this:

Array(unsigned int length_) : length(length_), ar(new T[length]) {}

is using length before it is constructed. Either change the class decl-order of member variables, or use length_ in the construction of ar.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • The constructor can use `length` just fine. – Rapptz Jun 13 '14 at 09:33
  • @Rapptz as written, no, it can't. It's value is indeterminate. If the order in the class decl is switched (as I said in my answer), *then* it is "just fine", as it will then be initialized *before* `ar`. – WhozCraig Jun 13 '14 at 09:34
  • 1
    The constructor can refer to `length` and expect a well-defined value if `length` has been initialized. Talk of the constructor is moot since the issue is the initializer list. – David Heffernan Jun 13 '14 at 09:35
  • @DavidHeffernan there has to be dozens of dupes for this, if I can find one I'm dropping this and linking it instead. Didn't know how much time the OP had to get an answer. – WhozCraig Jun 13 '14 at 09:38
  • Well, so much for dropping it. I can't drop an accepted answer (at least I don't have the brass to do so). Still, I linked [the duplicate I think best matches](http://stackoverflow.com/questions/8854354/does-the-order-of-base-class-initializers-and-member-variable-initializers-matte). Hopefully future readers pick it up. – WhozCraig Jun 13 '14 at 19:35