Реализовать класс одномерного массива

      Комментарии к записи Реализовать класс одномерного массива отключены

Главная Форумы Программирование Программирование на С++ Реализовать класс одномерного массива

В этой теме 2 ответа, 2 участника, последнее обновление  Васильев Владимир Сергеевич 1 год, 3 мес. назад.

  • Автор
    Сообщения
  • #2858

    questioner
    Участник

    Реализовать класс, представляющий собой одномерный массив. Должен содержать:

    1. конструктор, деструктор;
    2. функцию получения элемента по индексу;
    3. функцию добавления элемента в конец;
    4. функцию получения размера массива.

    Размер массива должен увеличиваться автоматически если не хватает места для вставки очередного элемента. Должны возбуждаться исключения, если:

    1. на вход функции, возвращающей элемент по индексу передано некорректное значение;
    2. не удалось выделить нужное количество памяти

    Работу с памятью желательно реализовать через функции malloc/free, т.к. в этом случае для увеличения размера массива можно использовать более эффективный realloc.

  • #2859

    Весь нужный вам функционал есть в стандартном классе vector, приведенный ниже код можно использовать лишь в учебных целях (чтобы потренироваться), во всех остальных случаях используйте надежные классы стандартной библиотеки.
    Объявим класс Array:

    template<class ElementType>
    class Array { 
    public:
      Array(); 
      ~Array(); 
     
      ElementType& operator [] (unsigned int index); 
      void push_back(const ElementType &item);
      ElementType* get();
      unsigned int size();
     
      struct bad_allocation {};
      struct bad_index {};
    private:
      ElementType *m_array;
      unsigned int m_size;
      unsigned int m_realSize;
     
      const static int Step = 128;
    };

    Тут функция получения элемента массива (оператор []) возвращает ссылку на элемент чтобы пользователь мог изменить принятое значение (изменить элемент массива). Функция добавления элемента также принимает константную ссылку на значение. Более подробно про передачу по ссылке.

    Класс помимо указателя на массив содержит его реальный размер (количество выделенной по указателю памяти) и количество записанных в массив элементов (меньше или равное реального размера). Константа Step хранит количество элементов, на которое увеличивается реальный размер всякий раз, когда очередной элемент не входит в существующий массив.

    Кроме того, описываются исключения, которые могут вырабатывать функции класса. На самом деле, более правильно — наследовать классы исключений от std::exception.

  • #2860

    Конструктор класса вызывает malloc чтобы выделить память. Если при этом он получить NULL — значит нужный блок памяти выделить не удалось, поэтому вырабатывается исключение:

    template <class ElementType>
    Array<Elementtype>::Array() : m_realSize(Step), m_size(0), m_array(0) { 
      m_array = (ElementType*)malloc(sizeof(ElementType)*m_realSize);
      if (0 == m_array) {
        throw bad_allocation();
      }
    }

    Вырабатывать исключения в конструкторе иногда опасно, однако в этом случае это допустимо, т.к. стандарт языка гарантирует при этом корректное освобождение памяти из под членов класса, созданных на стеке (m_realSize, m_size и указатель m_array). Утечки памяти, выделенной динамически (вызовом malloc) также не произойдет — ведь мы вырабатываем исключение только если память не удалось выделить. Подробнее: «Обработка исключений в конструкторе«.

    Деструктор убеждается что массив был создан (указатель не равен нулю) и освобождает память:

    template <class ElementType>
    Array<Elementtype>::~Array()  { 
      if (m_array)
        free(m_array);
    } 

    Строго говоря, в этом коде можно обойтись без проверки указателя, т.к. если мы добрались до деструктора, то паять однозначно была успешно выделена.

    Функции получения элементов и параметров массива:

    template <class ElementType>
    ElementType* Array<elementtype>::get() { 
      return m_array; 
    } 
    
    template <class ElementType>
    unsigned int Array<elementtype>::size() { 
      return m_size;  
    } 
     
    template <class ElementType>
    ElementType& Array<Elementtype>::operator [] (unsigned int index) { 
      if (index < 0 || index > m_size)
        throw bad_index();
      return m_array[index];
    }

    Наибольший интерес может представлять функция добавления элемента, т.к. она содержит код увеличения размера массива с помощью realloc:

    template <class ElementType>
    void Array<Elementtype>::push_back(const ElementType &item) { 
      if (++m_size > m_realSize) { 
        m_realSize += Step;
        
        ElementType *biggest_array;
        biggest_array = (ElementType *)realloc(m_array, sizeof(ElementType)*m_realSize);
     
        if (biggest_array == NULL) 
          throw bad_allocation();
        
        m_array = biggest_array;
      } 
     
      m_array[m_size-1] = item;
    }

    В случае ошибки выделения памяти функция realloc вернет нулевой указатель, а начиная с С++11 она не освобождает память по принятому указателю. Поэтому нельзя обойтись без вспомогательного указателя, в который требуется сохранить результат. Только в случае успешного выделения памяти содержимое m_array обновляется, в противном случае бросается исключение и память из под массива будет освобождена в деструкторе.

    Проверить работу функции можно следующим кодом:

    int main() { 
      Array<int> m_array;
    
      for(unsigned int i = 0; i < 15; i++) 
        m_array.push_back(rand() % 100);
      
    
      for(unsigned int i = 0; i < m_array.size(); i++) 
        cout << m_array[i] << " ";
      
      cout << endl;
      
      for(unsigned int i = 0; i < m_array.size(); i++) 
        m_array[i] = i;
      
      for(unsigned int i = 0; i < m_array.size(); i++) 
        cout << m_array[i] << " ";
    
      cout << endl; 
    }

    Вложения:

Для ответа в этой теме необходимо авторизоваться.