Critique my 2D array class?

I'd appreciate it if you guys could give me some feedback on my 2D array class :) Things I could do better, stuff I could add, stuff I should take out, etc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Array.h
// 2D Array implemented as a 1d array.
//
/* Ex:
 * A 2D array like
 * 1 2
 * 3 4
 *
 * is represented interally here by
 * 1 2 3 4
 *
 * myarray(0,0) returns 1,
 * myarray(1,1) returns 4, etc.
 *
 */


#ifndef PABLO_ARRAY_H
#define PABLO_ARRAY_H

#include <exception>

namespace exspace
{
    template <typename T>
    class Array
    {
        struct OutOfBounds : public std::exception
        {
            virtual const char* what() const throw()
            { return "Out of bounds index."; }
        };

        public:
            typedef unsigned int uint_t;

            // Construct a 2D array, size row x col.
            Array(const uint_t& row, const uint_t& col)
            : _rowSize(row), _colSize(col)
            { _ptr = new T[row*col]; }

            // Clean up resources.
            ~Array()
            { delete[] _ptr; }

            // Copy constructor.
            Array(const Array& toCopy) //const
            : _rowSize(toCopy._rowSize),
              _colSize(toCopy._colSize)
            // Not 100% sure about delete *this, but it would leak memory otherwise, right?
            { delete *this; this->_ptr = new T[_rowSize*_colSize]; }

            uint_t GetRowSize() const
            { return _rowSize; }

            uint_t GetColSize() const
            { return _colSize; }

            // Assignment operator.
            const Array& operator=(const Array&) const;

            // Checks first if the array sizes are equal, then
            // if every element in both arrays are equal.
            bool operator==(const Array& rhs) const;
            bool operator!=(const Array& rhs) const
            { return !(*this == rhs); }

            // Access a value within the vector at the provided position (row, col).
            T &operator() (uint_t row, uint_t col);

            // Overloaded to return a const value as well.
            const T &operator() (uint_t row, uint_t col) const;
        private:
            uint_t _rowSize;
            uint_t _colSize;
            T* _ptr;
    };

    template <typename T>
    const Array<T>& Array<T>::operator=(const Array& rhs) const
    {
        // Prevent self assignment.
        if (&rhs != this)
        {
            if (_rowSize != rhs._rowSize ||
                _colSize != rhs._colSize)
            {
                delete[] _ptr;
                _rowSize = rhs._rowSize;
                _colSize = rhs._colSize;
                _ptr = new T[_rowSize*_colSize];
            }

            for (int i=0; i<_rowSize*_colSize; i++)
                _ptr[i] = rhs._ptr[i];
        }
        return *this;
    }

    template <typename T>
    bool Array<T>::operator==(const Array& rhs) const
    {
        // Check if their dimensions are equal
        if (_rowSize != rhs._rowSize ||
            _colSize != rhs._colSize)
            return false;

        // Check each value for equality
        for (int i=0; i<_rowSize*_colSize; i++)
        {
            if (_ptr[i] != rhs._ptr[i])
                return false;
        }

        // If both are false, return true.
        return true;
    }

    template <typename T>
    const T& Array<T>::operator() (Array::uint_t row, Array::uint_t col) const
    {
        // If the requested position is within bounds,
        // return the element there.
        if (row < _rowSize && col < _colSize)
            return _ptr[(col*_rowSize)+row];
        else
            throw OutOfBounds();
    }

    template <typename T>
    T& Array<T>::operator() (Array::uint_t row, Array::uint_t col)
    {
        if (row < _rowSize && col < _colSize)
            return _ptr[(col*_rowSize)+row];
        else
            throw OutOfBounds();
    }

}


#endif // PABLO_ARRAY_H 
Says the person who doesn't know C++ *rolls eyes*

While I only skimmed it, it looks good so far. A few things:
-your assignment operator is const, though that doesn't really make any sense
-delete *this wouldn't compile - *this is a reference, and delete takes a pointer
-remove delete *this - I'm not sure what would happen if you did that...

Some added functionality that would be cool:
-a resize function
-maybe a function to print the contents of the array
Trying to be const-correct gave me a headache :/ Good catch.

For delete *this;, on second thought, it should probably be delete[] this->_ptr, right?

I considered adding a resize function, and I probably will - do you think I should also add a fill function? I'm not really sure how that would work in a 2D array, though...

Last edited on
No, because it's in the constructor. When an object is constructed, its values hold almost completely random values. delete[] this->_ptr would delete the memory at a random address in memory, likely crashing the program. Also, this-> anything is redundant in any member functions, because member variables automatically have this-> before them.
D'oh, don't know what I was thinking there. Thanks for the clarification.
closed account (4Gb4jE8b)
In my personal opinion (as a student of C++ and nothing more) It's better than i could currently do. I don't know how long you've been programming in this language, but i do know you've participated in these boards for longer (or at least more), and that you have a much deeper understanding of classes than i do. so there's my, granted pretty much useless feedback.
Topic archived. No new replies allowed.