Simple array implementation without bounds-checking I am preparing myself for some job interviews. This is a simple array (with the error handling left out for brevity). Any input or suggestions on style and the use of templates would be appreciated.

    #include &lt;iostream&gt;
    template &lt;class T&gt;
    class Array {
    public:
      explicit Array(const int&amp;);
      Array(const int&amp;, const T&amp;);
      Array(const Array&amp;);
      virtual ~Array();
      T getVal(const int&amp;) const;
      void setVal(const int&amp;, const T&amp;);
      T&amp; operator[] (T);
      Array&amp; operator= (const Array&amp;);

      template &lt;class U&gt;
      friend std::ostream&amp; operator&lt;&lt; (std::ostream&amp;, const Array&lt;U&gt;&amp;);

    private:
      T* arr;
      int size;
    };

    template &lt;class T&gt;
    Array&lt;T&gt;::Array(const int&amp; init_size) {
      arr = new T[init_size];
      size = init_size;
    }

    template &lt;class T&gt;
    Array&lt;T&gt;::Array(const int&amp; init_size, const T&amp; init_value) {
      arr = new T[init_size];
      size = init_size;
      for (int i = 0; i &lt; size; ++i) {
        arr[i] = init_value;
      }
    }

    template &lt;class T&gt;
    Array&lt;T&gt;::Array(const Array&amp; original) {
      size = original.size;
      arr = new T[size];
      for (int i = 0; i &lt; size; ++i) {
        arr[i] = original.arr[i];
      }
    }

    template &lt;class T&gt;
    Array&lt;T&gt;::~Array() {
      delete [] arr;
    }

    template &lt;class T&gt;
    T Array&lt;T&gt;::getVal(const int&amp; index) const {
      return arr[index];
    }

    template &lt;class T&gt;
    void Array&lt;T&gt;::setVal(const int&amp; index, const T&amp; value) {
      arr[index] = value;
    }

    template &lt;class T&gt;
    T&amp; Array&lt;T&gt;::operator[] (T index) {
      return arr[index];
    }

    template &lt;class T&gt;
    Array&lt;T&gt;&amp; Array&lt;T&gt;::operator= (const Array&amp; copy) {
      if (arr == copy.arr)
        return *this;
     size = copy.size;
      delete [] arr;
      arr = new T[size];
      for (int i = 0; i &lt; size; ++i) {
        arr[i] = copy.arr[i];
      }
      return *this;
    }

    template &lt;class T&gt;
    std::ostream&amp; operator&lt;&lt; (std::ostream&amp; out, const Array&lt;T&gt;&amp; self) {
      out &lt;&lt; "[ ";
      for (int i = 0; i &lt; self.size-1; ++i) {
        out &lt;&lt; self.arr[i] &lt;&lt; ", ";
      }
      out &lt;&lt; self.arr[self.size-1] &lt;&lt; " ]";
      return out;
    }
In the constructor that just takes a size. I would initialize all members to their default value even if POD.

template &lt;class T&gt;
Array&lt;T&gt;::Array(const int&amp; init_size)
{
  arr = new T[init_size]();
                  //    ^^^^^  Add braces. on types it makes no difference.
                  //           On POD it will force zero initialization.
  size = init_size;
}


Use the initializer lists in your constructors.

template &lt;class T&gt;
Array&lt;T&gt;::Array(const int&amp; init_size)
    : arr(new T[init_size]())
    , size(init_size)
{}


Use copy and swap idiom for assignment operator (it automatically provides the strong exception guarantee).

template &lt;class T&gt;
Array&lt;T&gt;&amp; Array&lt;T&gt;::operator= (const Array&amp; copy)
{
    if (arr == copy.arr)  // This is the wrong test.
        return *this;     // Though it works as a side effect you will confuse the maintainer.

    size = copy.size;
    delete [] arr;       // breaks the strong exception gurantee.
                         // What it the next line fails? Then you are left with an object
                         // in an inconsistent state. (arr points at de-allocated memory)
    arr = new T[size];

    for (int i = 0; i &lt; size; ++i)
    {
        arr[i] = copy.arr[i];
    }
    return *this;
}


If you want to do this the hard way then it should look like this:

template &lt;class T&gt;
Array&lt;T&gt;&amp; Array&lt;T&gt;::operator= (const Array&amp; copy)
{
    if (this == &amp;copy)    // Return quickly on assignment to self.
    {   return *this;
    }

    // Do all operations that can generate an expception first.
    // BUT DO NOT MODIFY THE OBJECT at this stage.
    T* tmp = new T[size];
    for (int i = 0; i &lt; size; ++i)
    {
        tmp[i] = copy.arr[i];
    }

    // Now that you have finished all the dangerous work.
    // Do the operations that  change the object.
    std::swap(tmp, arr);
    size = copy.size;

    // Finally tidy up
    delete tmp;    // Notice the swap above.

    // Now you can return
    return *this;
}


Alternatively use the copy and swap idiom

template &lt;class T&gt;
Array&lt;T&gt;&amp; Array&lt;T&gt;::operator=(Array const&amp; rhs)
{
    // 1 Copy
    Array    copy(rhs);     // Use the copy constructor to make a safe copy.

    // 2 Swap
    swap(arr,   copy.arr);
    swap(size,  copy.size);

} // 3 as the local copy goes out of scope it destroys the old array.


Note this can be optimized too:

Array&lt;T&gt;&amp; Array&lt;T&gt;::operator=(Array rhs) // 1 implicit copy as parameter is passed by value
{
    // 2 Swap
    swap(arr,   copy.arr);
    swap(size,  copy.size);

} // 3 as the local copy goes out of scope it destroys the old array.


You don't need a get/set methods. Infact get/set is an obvious indication of bad design.

template &lt;class T&gt;
T Array&lt;T&gt;::getVal(const int&amp; index) const {
  return arr[index];
}

template &lt;class T&gt;
void Array&lt;T&gt;::setVal(const int&amp; index, const T&amp; value) {
  arr[index] = value;
}


Just remove both these methods. What you want to do is return a reference to the internal object in your overload of operator[] (which you do) bit the index is an integer usually.

template &lt;class T&gt;
T&amp; Array&lt;T&gt;::operator[] (size_t index)
{                //      ^^^^^^^    Changed type here.
  return arr[index];
}


You also need to provide a verision to use when your array is const.

template &lt;class T&gt;
T const&amp; Array&lt;T&gt;::operator[] const (size_t index)
//^^^^^   Here                ^^^^^  and here.
{
  return arr[index];
}


If you provide an output operator you should generally by symmetric and provide an input operator.