Универсальный шаблон массива (n-мерного, n >= 1)
От: Green Chest Россия  
Дата: 07.09.08 08:33
Оценка:
Здесь, на rsdn много раз обсуждались многомерные массивы (представлять как одномерные и проч.), но я среди обсуждений не нашёл именно того, что мне нужно.
Необходимо сделать объект — оболочку для массивов, для удобства работы с массивами. (Проблема стара как мир )
Т.е. обычным на С++ выглядит следующее:

{
     //Размерность первая
    const unsigned int s1 = 4;
     //Размерность вторая
    const unsigned int s2 = 8;
     //Временный массив для передачи данных функции
    int **arr = new int*[s1];
    for(unsigned int i=0; i<s1; i++)
        arr[i] = new int[s2];
        
     //Заполняем массив
    for(unsigned int i=0; i<s1; i++)
        for(unsigned int j=0; j<s2; j++)
            d[i][j] = <какое-то значение>;
            
     //Вызываем некий метод некого объекта(это всё не важно, главное что ему
     //требуется указатель на указатель, являющийся массивом целых чисел)
     //прототипа навроде такого: setAD2(int** a, unsgined int size1, unsigned int size2)
    fv.setAD2(arr, s1, s2);
     //Метод забрал часть данных из двухмерного массива в своё внутренее хранилище,
     //о котором мы ничего не знаем и знать не хотим, массив нам больше не нужен
        
     //Освобождаем память
    for(unsigned int i=0; i<s1; i++)
        delete[] arr[i];
    delete[] arr;
}


Утомляет всё это писать, хочется написать выделение и освобождение памяти раз и навсегда ( для всех массивов), чтобы можно было так:

{
     //Объявили массив и выделили память
    Array<int> a(10);

     //Заполняем массив
    for(unsigned int i=0; i<a.size(); i++)
        d[i] = <какое-то значение>;
    
     //Вызвали функцию требующу указатель на инт, являющийся массивом и размер массива
    funcAr(a.getPoint(), a.size());
    
     //Деструктор вызовется автоматически и 
     //беспокоится о не освобождении памяти не нужно
}


Это легко реализовать с помощью вот такого шаблона (привожу очень упрощенный вид):

template <typename type> class A
{
  private:
     type *arr;
  public:
    A() : arr(0) {};
    A(int x) {arr = new type[x];};
   type& opertor [] (int index) {return arr[index];};
};


Однако в таком случае для n-мерного массива (в примере ниже n=2) потребуется опять таки выделять память для каждого измерения:

{
    A<A<int> > ob1(10);   //Получается память будет выделена только под одно измерение, как выделить под другое?
    a[3][8] = 5;  //ошибка, обращаемся к памяти по "левому" адресу
     //Возможно сделать некий метод класса А под названием getMem, выделяющий память и вызывать его так:
    for(unsigned int i=0; i<ob1.getSize(); i++)
        ob1[i].getMem(10);

    a[3][8] = 5;
     //всё отлично, память выделена
    assert(a[3][8] == 5);
}


Решение рабочее, но не красивое — уж лучше вообще без объектов, просто int** и ему выделять память.
Тогда пришла идея сделать шаблон с параметром, вот такой:

template <typename type, unsigned int size> class A
{
  private:
     type *arr;
  public:
    A() : {arr = new type[size];};
   type& opertor [] (int index) {return arr[index];};
};

Тогда код (1)
{
  A<A<int, 10>, 10> ob1; 
  a[3][8] = 5;  //всё отлично, память выделена
}

...работает. Но не более.
Дальше начинаются извращения, например чтобы присваивать (кажется логичным массиву из 10 целочисленных элементов присвоить массив из 9 целочисленных элементов, просто скопировав 9 значений) надо делать приведение типов. Что-то типа такого (привожу упрощенный вариант):

template <size_t len2, typename U> Arr<T, len> & operator= (Arr<U, len2> & arr2)
{
    for (int j = 0; j < len2; ++j)
        arr[j] = arr2[j];
    return *this;
}


Да и вообще в коде (1) мы уже не имеем возможности создавать как таковые динамические массивы, параметру шаблона нужно передавать константу. И функции, требующей на входе двумерный массив, не понятно нак передавать его, если он хранится в виде A<A<int, 10>, 10>, получается одномерный массив объектов (одномерных массивов целых чисел) — это не то что нам нужно.

Итак. Я хочу создать некий пользовательский тип(класс), который позволит работать вот так (примерно так):

{
    Array<Array<int>> a; //Здесь каким-то образом задаю обе размерности
    a[7][5] = 5;
    std::cout << a[7][5] << endl;
    Array<Array<int>> b; //Другого размера, нежели a
    b = a; //Копирует значения (те которые поместятся, т.к. размер может быть и меньше)
    b.reSize(50); //Перевыделяет память и копирует значения
    a.newSize(100); //Освобождает занятую память и выделяет новый блок под сто элементов
    Array<Array<int>> c(b); //Конструктор копирования, если у c и b разные мерности,
     //то хочется чтобы такой код был определён как ошибачный на стадии компиляции
     //И главная цель - вызов функции с прототипом похожим на вот такой func(int** a, int s1, int s2),
     //каким-нибудь простым способом, например таким:
    func(a.getPoint(), a.size(), a[0].size());    
}



Спасибо большое всем кто прочитал и что-то придумал.



Ещё раз (кратко), я хочу:
Создать объект — многомерный массив. Он должен:
1. выделять память, освобождать память, не утруждая этим клиентский код;
2. иметь возможность его использования там где требуется int** (на месте инта — любой тип, на месте двух
звёздочек — любое количество звёздочек (равное мерности массива));
3. уметь менять свой размер по требованию, уже после создания (т.е. что-то типа reSize, newSize описанных
выше);
4. использовать конструкторы копирования, перегруженные операторы присваивания для массивов однинаковой
мерности и типа, но разных размерностей.



Помогите, поделитесь, пожалуйста, любыми мыслями (отсылать меня использовать готовые библиотеки не нужно, посылать совсем далеко то же), советами, как реализовать эти 4 пункта!
Искал, то что хочу не нашёл. В std есть valarry, но 2 пункт (а для него всё это и делалось) не удет с ними работать, да и 4 прийдётся переписать самому. Перечитал главу про шаблоны у Б. Страуструпа, прочитал про шаблоны у Р. Лафоре, листал А. Александреску (жёстко написано, не дорос я ещё до него).
Заранее огромное спасибо всем, кто хоть что-то напишет, прочитав моё сообщение!
(Я уже давно е...сь с этой идеей. (е...сь — еграюсь ))
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.