Использование массивов в качестве параметров шаблона в моем элементарном векторном классе - PullRequest
0 голосов
/ 20 августа 2011

Исходя из фона PHP, я пытаюсь изучать C ++, так как я нахожу это интересным языком.В качестве практики я хочу создать простой класс Vector с использованием шаблонов, что не сложно.Однако я сталкиваюсь с одной проблемой.

Я создал следующий шаблонный класс:

template <typename T>
class Vector
{
public:
    Vector(int length);
    ~Vector(void);
    int getLength();

    T& operator[] (const int index);

private:
    T *_items;
    int _count;
};


template <typename T>
Vector<T>::Vector(int length)
{
    _items = new T[length];
    _count = length;
}

template <typename T>
T& Vector<T>::operator[]( const int index )
{
    if (index >= getLength() || index < 0)
        throw exception("Array out of bounds.");
    return _items[index];
}

Все функции реализованы, но они не относятся к моему вопросу, поэтому я не имеюя скопировал их сюда.

Этот класс работает, как и ожидалось, за одним исключением: если я хочу создать вектор массива, он не будет работать.Например:

Vector<int[2]> someVector(5);

Очевидно, что я хочу, чтобы свойство _items векторного класса было int [5] [2].Однако, поскольку компилятор заменяет 'T' на 'int [2]', свойством _items будет int [2] [5] (или, по крайней мере, это я понял из отладки, пожалуйста, исправьте меня, если я ошибаюсь).В результате оператор [] больше не работает правильно, и поэтому весь этот класс бесполезен для массивов.

Есть ли способ решить эту проблему, чтобы этот класс также работал для массивов?И если это невозможно, есть ли способ предотвратить инициализацию этого класса массивами?

Редактировать: Спасибо за все ваши ответы.Тем не менее, я мог быть не совсем понятен с моим вопросом.Прежде всего, я создал этот класс, чтобы привыкнуть к c ++, я знаю, что есть класс std :: vector, и я также теперь, когда лучше использовать вектор векторов.Это не совсем проблема.Я просто хочу лучше понять шаблоны, и c ++ в целом, поэтому я хочу знать, как решать проблемы такого типа.Я хочу иметь возможность создавать классы, которые не вызывают сбой программы.Если бы я или кто-то другой использовал бы этот класс прямо сейчас и попытался бы использовать примитивные массивы вместо векторов для этого класса, в какой-то момент программа потерпит крах, поскольку массив неверен (Vector (y) становится int [x] [y] вместо int [y] [x] внутри).Поэтому мне нужно решение, которое либо создает правильный массив, либо вообще запрещает инициализацию вектора массивами.

Ответы [ 3 ]

7 голосов
/ 20 августа 2011

Проще говоря, никогда не используйте встроенные примитивные массивы. Для всего. Они ужасно сосут. Всегда используйте обертку класса, такую ​​как boost::array, если у вас нет TR1 или C ++ 0x, оба из которых также предоставляют класс array. Vector<boost::array<int, 2>> скомпилируется тривиально.

Почему бы не использовать примитивные массивы?

У них отвратительные неявные преобразования в указатели, они забывают о своем размере на мгновение, не являются первоклассными гражданами (например, не могут назначить их), не проверяют свои границы, например. boost::array<int, 2> - это примитивный массив без дрянных преобразований, он полностью универсален - например, ваш шаблон Vector отлично работает с boost::array<int, 2> с нуля, и он может выполнять проверку границ в функции at().

Я не предлагаю вместо этого использовать динамический массив. boost::array не является динамически изменяемым массивом. Это массив с типом значения постоянного размера, который не будет преобразован в указатель, у него есть функции для использования в стандартной библиотеке, такие как begin, end, size, и он может обрабатываться как любой другой тип: в отличие от массивов, которые имеют десяток специальных правил - как вы узнали.

5 голосов
/ 20 августа 2011

Я вижу несколько вещей не так с этим.

  1. Если вы создаете общий векторный класс, зачем иметь дело с вектором массивов, а не вектором векторов?

Вместо определения вектора типа int [2], попробуйте создать вектор векторов размера 2 примерно так:

Vector<Vector<int>> vector(5);
for (int i = 0; i < 5; i++)
{
    vector[i] = Vector<int>(2);
}
  1. Вместо того, чтобы использовать массив постоянного размера, попробуйте использовать указатель.

Вместо использования указателя на массивы размера 2 используйте указатель на указатель и выделите два пробела для этого указателя.С указателями гораздо проще работать в C ++, потому что вы можете просто передать адрес указателя, а не копировать весь массив.Обычно это очень плохая форма для передачи массивов.

  1. Добавить параметр по умолчанию в ваш конструктор

Вместо объявления конструктора с помощью Vector(int length);, попробуйте использовать Vector(int length = 0);что если пользователь не укажет длину, он по умолчанию будет равен нулю.

Наконец, знаете ли вы, что на самом деле существует std :: vector, или вам известно об этом, и вы просто пытаетесьповторить это?Известно, что шаблоны - одна из самых сложных тем в C ++, удачи!

0 голосов
/ 20 августа 2011

Условие должно содержать index >= getLength(), потому что getLength () тоже недопустимое значение индекса (индекс первого элемента 0, последний getLength()-1)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...