LINUX.ORG.RU

Ответ на: комментарий от qulinxao

Вот я читаю, пишу, как надо, а оно не компилируется! Кто виноват, тупой читатель или хреновый автор? Я не считаю Страуструпа хреновым, но, если бы, книга была толще в 10 раз, и каждая тема капитально разжевывалась, и все объяснялось на пальцах, и было бы очень много примеров, желательно, отдельная книга с примерами, то мне было бы гораздо легче изучить C++.

puding
() автор топика
Ответ на: комментарий от puding

как раз таки толщина слишком большая.

если уж через динамику велосипедить

велосипедь класс (можно генерик) - row of T

затем велосипедь класс table of T as ( col of row of T)

а ежель ты хочеш * то *** и ** это не культурно.

qulinxao ★★☆
()
Ответ на: комментарий от qulinxao

Ладно, закрываю тему. И подучу язык, как следует. Как найду решение, отпишусь, если не забуду. Может кому пригодится.

puding
() автор топика
Ответ на: комментарий от comp00
#include <memory>
#include <cstdio>

template <typename T, size_t rows, size_t cols>
using Matrix = T[rows][cols];

int main()
{
    std::unique_ptr<Matrix<int, 4, 4>> array(new int[1][4][4]);

    for (auto const& row : *array) {
        for (auto const& el : row) printf("%p ", &el);
        puts("");
    }

}

/*

0x59f9040 0x59f9044 0x59f9048 0x59f904c 
0x59f9050 0x59f9054 0x59f9058 0x59f905c 
0x59f9060 0x59f9064 0x59f9068 0x59f906c 
0x59f9070 0x59f9074 0x59f9078 0x59f907c

 */

/*

  total heap usage: 1 allocs, 1 frees, 64 bytes allocated

 */
quasimoto ★★★★
()
Ответ на: комментарий от comp00

с было собственным подмножеством дай бог до С89 (С ANSI) уже для C99 были десигндесишнс которые были иначе решены в С++

qulinxao ★★☆
()
Ответ на: комментарий от puding

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

#include <stdlib.h>
#include <stdio.h>

class MYCLASS
{
 public:
 int val;
 void print()
 {
 printf("%d\n",val); 
 };
} ;

#define WIDTH  3
#define HEIGHT 2

typedef MYCLASS* A[WIDTH][HEIGHT];

void print(A * a , int x,int y)
{
 for(int i=0;i<x;i++)
 for(int j=0;j<y;j++)
 { 
  printf("[%d][%d]",i,j);
  (*a)[i][j]->print();
 }
}

int main(void)
{
 A* a=(A*)malloc(sizeof(void*)*WIDTH*HEIGHT);
 
 for(int i=0;i<WIDTH;i++)
 {
  for(int j=0;j<HEIGHT;j++)
  { 
   (*a)[i][j]=new MYCLASS;
   (*a)[i][j]->val=100*i+j;
  }
 }
 printf("\n");
 print(a,WIDTH,HEIGHT);
 return 0;
}
ilovewindows ★★★★★
()
Ответ на: комментарий от comp00

С подмножество С++ => разочаровавшись в С++ (в более мощном множестве), ты разочаровываешься в С (менее мощное множество, содержащее в большем).

C и C++ — пересекающиеся множества => остальная твоя логическая цепочка неверна.

cPunk ★★
()
Ответ на: комментарий от trex6

Про экономию на спичках — http://www.agner.org/optimize/optimizing_cpp.pdf.

В частности

A multidimensional array should be organized so that the last index changes fastest. This makes sure that the elements are accessed sequentially. The opposite order of the two loops would make the access non-sequential which makes the data caching less efficient.

A matrix or multidimensional array should be stored in one contiguous memory block. Do not use one container for each row or column. The access is faster if the number of elements per row is a constant known at compile time.

implementing a matrix in STL as a vector of vectors, as is often seen, is certainly a very inefficient solution.

Про обход больших матриц и prefetch там же.

quasimoto ★★★★
()
Ответ на: комментарий от anonymous

Так как-то спокойнее на душе, физический смысл нагляднее - массив из указателей длина такая-то. Лишнее напоминание что это за фигня такая А, способ впасть в особое состояние духа, типа поедания мухоморов перед боем или дыхательной гимнастики. Ну ты понел.

ilovewindows ★★★★★
()
Ответ на: комментарий от puding

Вот я читаю, пишу, как надо, а оно не компилируется! Кто виноват, тупой читатель или хреновый автор?

и то и другое. Автор подразумевал, что вам известен C. ИЧСХ, K&R подразумевали, что вам известен _другой_ ЯП.

Hint: начните с чего-то попроще.

emulek
()
Ответ на: комментарий от emulek

Почему на полпути, наоборот, спустился к первоэлементам, ибо сначала было void*, а всё остальное суета.

ilovewindows ★★★★★
()
Ответ на: комментарий от ilovewindows

Так как-то спокойнее на душе, физический смысл нагляднее

ну и забудешь потом при изменении типа A изменить выделение памяти и влетишь в проблемы с памятью.

anonymous
()

Ну вообще-то это делается так же как и в C.
Поэтому всё же изучая C++ лучше начинать с C.
Если массив динамический - значит память нужно выделять «вручную» то есть программно.

На C это примерно так делается:

#include <malloc.h>
#include <math.h>
#include <stdio.h>

typedef struct { int m, n; double *e; } matrix;

matrix *matrix_create(int m, int n);
void matrix_free(matrix *a);
int matrix_set(matrix *a, int i, int j, double v);
int matrix_get(matrix *a, int i, int j, double *v);

// Создание матрицы
matrix *matrix_create(int m, int n) {

    matrix *a = NULL;
    if (m > 0 && n > 0 && ((a = (matrix *) malloc(sizeof(matrix))) != NULL)) {

        a->m = m;
        a->n = n;
        if ((a->e = (double *) malloc(sizeof(double) * m * n)) != NULL)
        for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) matrix_set(a, i, j, 0);
        else { free(a); a = NULL; }
    }
    return a;
}

// Освобождение матрицы
void matrix_free(matrix *a) { free(a->e); free(a); }

// Присвоение значения элементу матрицы
int matrix_set(matrix *a, int i, int j, double v) {

    int ret = i > 0 && j > 0 && i <= a->m && j <= a->n;
    if (ret) *(a->e + (i - 1) * a->n + j - 1) = v;
    return ret;
}

//  Получение элемента матрицы
int matrix_get(matrix *a, int i, int j, double *v) {

    int ret = i > 0 && j > 0 && i <= a->m && j <= a->n;
    if (ret) *v = *(a->e + (i - 1) * a->n + j - 1);
    return ret;
}

// Пример использования
int main(void) {

    double v;
    matrix *a = matrix_create(3, 3);
    matrix_set(a, 1, 1, M_PI);
    matrix_set(a, 2, 2, 2 * M_PI);
    matrix_set(a, 3, 3, M_PI * M_PI);
    for (int i = 1; i <= 3; i++) for (int j = 1; j <= 3; j++) {

        matrix_get(a, i, j, &v);
        printf("%f%s", v, j == 3 ? "\n" : " ");
    }
    matrix_free(a);
    return 0;
}

Переделать это в класс C++ в общем-то не так сложно.
Куда важнее понять принцип работы с памятью или с динамическими массивами в данном случае.

Для того что бы уж совсем «динамической» матрицу сделать к тем функциям которые я привел нужно добавить ещё одну, что-то вроде matrix_recreate.
Но это ты уж сам. Домашнее задание так сказать) Подсказка — нужна функция realloc.
И после этого тред можно считать закрытым а то развели флейм.

user0xff
()
Ответ на: комментарий от user0xff

if ((a->e = (double *) malloc(sizeof(double) * m * n)) != NULL)
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++) matrix_set(a, i, j, 0);
else { free(a); a = NULL; }

if (!(a->e = calloc(m * n, sizeof(double)))) { free(a); a = NULL; }

Вместо int должно быть size_t и индексация с нуля — проверки на > 0 и вычитания единиц не нужны.

В c99 есть flexible array members — matrix_free не нужен.

В си есть хороший сахар для *(ptr + offset) :)

Приведения (void*) -> (T*) не нужны.

Ещё я бы добавил const и заменил проверки на assert (так что возвращение double у matrix_get).

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct { size_t m, n; double e[]; } matrix;

matrix* matrix_create(const size_t m, const size_t n)
{
    matrix *a = NULL;
    if ((a = calloc(sizeof(matrix) + m * n * sizeof(a->e[0]), 1))) {
        a->m = m; a->n = n;
    }
    return a;
}

void matrix_set(matrix *const a, const size_t i, const size_t j, const double v)
{
    assert(i < a->m && j < a->n);
    a->e[i * a->n + j] = v;
}

double matrix_get(const matrix *const a, const size_t i, const size_t j)
{
    assert(i < a->m && j < a->n);
    return a->e[i * a->n + j];
}

#define M_PI 3.14159265358979323846

int main()
{
    matrix *const a = matrix_create(3, 3);
    matrix_set(a, 0, 0, M_PI);
    matrix_set(a, 1, 1, M_PI * M_PI);
    matrix_set(a, 2, 2, M_PI * M_PI * M_PI);

    for (size_t i = 0; i < 3; ++i)
        for (size_t j = 0; j < 3; ++j)
            printf("%f%s", matrix_get(a, i, j), j == 2 ? "\n" : " ");

    free(a);
}
quasimoto ★★★★
()
Ответ на: комментарий от puding

При проверке выхода за границы.

У вектора в операторe[] нет проверки выхода за границу. Она есть только в методе at.

DarkEld3r ★★★★★
()
Ответ на: комментарий от anonymous

А что можно поменять в типе А ? Размер указателя, длина массива постоянные, при изменении требуют компиляции. И вообще скучный код. Надо все выкинуть.

#include <stdlib.h>
#include <stdio.h>

class MYCLASS
{
 public:
 int val;
};

class TROW
{
  int size;
  MYCLASS** cells;
 public:
  
  TROW(int n)
  {
   size=n;
   cells=(MYCLASS**)malloc(sizeof(void*)*n);
   for(int i=0;i<n;i++) cells[i]=new MYCLASS;
  };
  
  MYCLASS*& operator[] (int i)
  {
	 return  cells[i];
  }; 
 };

class TMATRIX
{
 TROW** rows;
 public:
  int row_count;
  int col_count;

  TMATRIX(int n,int m)
  {
   row_count=n;
   col_count=m;
   rows=(TROW**)malloc(sizeof(void*)*n);
   for(int i=0;i<n;i++) rows[i]=new TROW(m);
  };
  
  TROW& operator[] (int i)
  {
	 return  *rows[i];
  };
};

int main(void)
{
 int WIDTH=3;
 int HEIGHT=4;

 TMATRIX m(WIDTH,HEIGHT);
 
 for(int i=0;i<WIDTH;i++)
 for(int j=0;j<HEIGHT;j++)
 {
  m[i][j]->val=(i*100+j);
 }
 
 for(int i=0;i<WIDTH;i++)
 for(int j=0;j<HEIGHT;j++)
 {
  printf("[%d][%d]=%d\n",i,j,m[i][j]->val);
 }
 
 return 0;
}

ilovewindows ★★★★★
()
Ответ на: комментарий от quasimoto

Главное человека не запутать.
А так да. Хорошо.
Ну что, теперь ждем matrix_recreate (а лучше matrix_resize)? :)
Но это puding уже сам пусть попробует сделать.
Иначе как-то без изменения размерности матрицы (читай двухмерного массива) это и не динамика как бы.
Ну так, приближение только к ней.
Двухмерный массив есть, но от адреса на него правда почти ушли и динамика как бы на половину.

user0xff
()

ЛОР в красе.

anonymous
()
Ответ на: комментарий от user0xff

изменения размерности матрицы

матрицы

vector это не вектор (с) Степанов :) С resize это «динамический массив», соответственно, динамический массив динамических массивов (может быть ещё и разного размера) это не вполне матрица.

А «динамичность» вектора или матрицы тут в неизвестности m и n (антипод — статичность, то есть известность их во время компиляции).

1. Из того что приводил ТС непонятно нужен ли ему resize, но я видел известность m и n — может хватит простого T[m][n] или std::arraty<std::array<T, m>, n> которые передаются элементарно по значению указателя для массива и по значению (если нужно копирование) или по ссылке для std::array.

2. Если m и n неизвестны (постоянны или нет с resize) — лёгкий класс Matrix будет минимальным заголовком (begin, m, n или begin, end, m/n) который будет накатываться конструктором на стеке и делать ту же единственную аллокацию куска в куче и указывать на неё. Передаётся по ссылке (тут будет два разыменования вместо одного во варианте с flexible array members) или по значению (с конструктором копирования). Стандартные std::string и std::vector обычно так устроены — в гнутой реализации одно это слово {begin}, другое — три слова {begin, end, capacity_end}.

3. Если это jagged array — std::vector<std::vector<T>>. Передаётся так же — по ссылке или по значению с копированием.

quasimoto ★★★★
()
Ответ на: комментарий от puding

Понаписали то сколько изверги. А надо было просто сказать в ответ ТС'овский на код

const int QwMatrixWidth = 20;
const int  QwMatrixHeight = 20;

QwMatrixElement QwMatrix[QwMatrixHeight][QwMatrixWidth];

void QwDrawMatrix(QwMatrixElement** matrix, int n, int m) {

    //Производятся операции над элементами матрицы

}

что двумерный массив и указатель на указатель - не эквивалентные и не «взаимотрансформируемые» вещи.

ТС, почитай где нибудь, что в C/C++ есть два основных типа памяти под используемые объекты - стек и хип. То, что в стеке, создается автоволшебно, то что в хипе создается через new/*alloc и достается через указатели.

Свою матрицу ты создал в стеке, так что она уже заполнена, и в памяти лежит последовательно. То есть массив 2x3 лежит в памяти так

 row0col0 |  row0col1 | row0col2 |  row1col0 |  row1col1 | row1col2 

Один из методов делать итерацию по указателю на указатель (далее УнУ) такой:

// где-то ранее инициализироан int **pp  ;
for (int i = 0; i<rows; i++ ){
		for (int j=0; j<columns; j++) {
			//pp {+X} - указатель на строку
			//*pp {+Y}- указатель на столбец
			//**pp - значение в ячейке
			std::cout << *(*(pp+i)+j) << " " ;
		}
		std::cout << "\n";
	}

Теперь представь, ты передал в функцию свою матрицу приведя ее тип к УнУ. В этом случае в pp будет адрес ячейки row0col0, а вот в *pp уже будет значение ячейки row0col0, например -10. Поэтому когда ты попробуешь обратиться к **pp, то программа попробует прочитать память по адресу -10, в результате чего встретится с отцом и великим повелителем всех программистов С/С++ - сигналом №11, более изветсном в Рунетах как «Ошибка сегментации».

Короче, чтобы у тебя заработало в твоих изначальных условиях передавай указатель, а не УнУ. Пример:

#include <iostream>
class CC {
public:
	int aa;
	CC() {aa=10;};
};

void drawCC (CC* cc, int rows, int columns) {	
	for (int i = 0; i<rows; i++ ){
		for (int j=0; j<columns; j++) {
			std::cout << "aa:" << (cc+i*rows+j)->aa+10*i+j << " " ;
		}
		std::cout << "\n";
	}
}

int main(int argc, char **argv)
{

	int rows;
	int columns;	
	std::cin >> rows >> columns ;

	CC cc[rows][columns];
	
	drawCC(reinterpret_cast<CC*> (&cc),rows,columns);
	
	return 0;
}

ЗЫ: Да, из C++ здесь только class, iostream и reinterpret_cast, остальное чистый С, но с ним всегда так - говоришь Партия, подразумеваешь Ленин и т.д.

codeogre
()
Ответ на: комментарий от ilovewindows

А что можно поменять в типе А ?

#define WIDTH  3
#define HEIGHT 2

typedef MYCLASS* A[WIDTH][HEIGHT];

добавляешь новый макрос HEIGHT_NEW и меняешь в типе A макрос HEIGHT на HEIGHT_NEW

#define WIDTH  3
#define HEIGHT 2
#define HEIGHT_NEW 8

typedef MYCLASS* A[WIDTH][HEIGHT_NEW];
и не предполагаешь что дальше в коде существует подленькая строчка:
A* a=(A*)malloc(sizeof(void*)*WIDTH*HEIGHT);
все успешно соберется, но ошибка указания неправильного размера в выделении памяти будет.

про второй вариант с 3-мя классами. так делать нельзя.

anonymous
()
Ответ на: комментарий от anonymous

Хорошо, не буду делать так. А так можно ?

#include <stdlib.h>
#include <stdio.h>


class TMATRIX
{
 TMATRIX** rows;
 public:
  int val;

  TMATRIX(int * size)
  {
   int n=size[0];
   size++;
   rows=(TMATRIX**)malloc(sizeof(void*)*n);
   for(int i=0;i<n;i++)
   {
    if(n) rows[i]=new TMATRIX(size); else rows[i]=this;
   } 
  }

  TMATRIX& operator[] (int i)
  {
	 return  *rows[i];
  };
};


int main(void)
{
 int size[4]={2,3,4,0};

 TMATRIX m(size);
 
 for(int k=0;k<2;k++)
 for(int i=0;i<3;i++)
 for(int j=0;j<4;j++)
 {
   m[k][i][j].val=(k*100+i*10+j);
 }

 for(int k=0;k<2;k++)
 for(int i=0;i<3;i++)
 for(int j=0;j<4;j++)
 {
  printf("[%d][%d][%d]=%d\n",k,i,j,m[k][i][j].val);
 }
 
 return 0;
}

ilovewindows ★★★★★
()
Ответ на: комментарий от ilovewindows

А так можно ?

Нельзя :) Вот пример в котором 1) есть хоть какие-то соглашения о стиле, 2) работает для тензоров любого ранга, 3) более типобезопасен, то есть нельзя сделать t(1, 2, 3, 4) для тензора третьего ранга или недодать размеров тензору, например, 4) работает в пару-другую раз быстрее (это как я замерил), 5) и опять выделяет память компактно один раз — расходуется её в пару-другую-третью раз меньше и с отсутствием роста pagefault-ов (так time сказал).

#include <array>
#include <numeric>
#include <functional>

template <size_t length, size_t from_end>
struct static_product;

template <size_t length>
struct static_product<length, 1> {
    template <typename T>
    static T result(std::array<T, length> const& array) {
        return array[length - 1];
    }
};

template <size_t length, size_t from_end>
struct static_product {
    template <typename T>
    static T result(std::array<T, length> const& array) {
        return array[length - from_end] * static_product<length, from_end - 1>::result(array);
    }
};

template <typename A, typename... As>
std::array<A, 1 + sizeof...(As)> make_array(A a, As... as) {
    std::array<A, 1 + sizeof...(As)> array = { { a, as... } };
    return array;
}

template <typename T, size_t rank>
struct tensor {

    typedef T value_type;
    typedef std::array<size_t, rank> size;

    const size sizes;

private:

    T *data;

public:

    tensor(size const& sizes_) :
        sizes(sizes_),
        data(new T[std::accumulate(sizes_.begin(), sizes_.end(), 1,
                                   std::multiplies<size_t>())]) {}

    template <typename... As>
    tensor(size_t size, As... sizes_) : tensor(make_array(size, sizes_...)) {}

    ~tensor() { delete[] data; }

    template <size_t>
    size_t toOffset(size_t index) { return index; }

    template <size_t from_end, typename... As>
    size_t toOffset(size_t index, As... indexes) {
        return index * static_product<rank, from_end>::result(sizes) +
               toOffset<from_end - 1>(indexes...);
    }

    template <typename... As>
    T& operator()(As... indexes) {
        return data[toOffset<rank - 1>(indexes...)];
    }
    // ^ Tensor<long, 3> :
    //
    // imulq	8(%rdi), %rsi
    // movq	24(%rdi), %rax
    // addq	%rdx, %rsi
    // imulq	16(%rdi), %rsi
    // addq	%rcx, %rsi
    // movq	(%rax,%rsi,8), %rax
    // ret

    T& get1(size_t index) { return data[index]; }

};

#include <cstdio>
#include <iostream>

int main()
{
    size_t I, J, K;
    std::cin >> I >> J >> K;

    tensor<long, 3> t(I, J, K);

    for(size_t i = 0; i < I; ++i)
        for(size_t j = 0; j < J; ++j)
            for(size_t k = 0; k < K; ++k)
                t(i, j, k) = long(i * 100 + j * 10 + k);

    // t(); <- error
    t(0);
    t(0, 0);
    t(0, 0, 0);
    // t(0, 0, 0, 0); //<- error
    // ...

    for(size_t i = 0; i < I; ++i)
        for(size_t j = 0; j < J; ++j)
            for(size_t k = 0; k < K; ++k)
                printf("t(%ld, %ld, %ld) = %ld (%p)\n",
                       i, j, k, t(i, j, k), &t(i, j, k));
}
quasimoto ★★★★
()

Забавно. У меня в функциях и такое встречалось: void function(float ****arg, ...)

Anon
()
Ответ на: комментарий от quasimoto

1) Стиль «нечитаемая шняга» :D 2) не является уникальной фичей 3) не факт 4) не критично,скорость написания программ для которых это проявится (или не проявится) во много раз меньше скорости роста производительности процессоров 5) Стратегия выделения памяти делается конкретно под задачу переписыванием new

6) Не компиляется, школьники негодуют. 7) И где тут «классический» вид x[j][k] ?

ilovewindows ★★★★★
()
Ответ на: комментарий от ilovewindows

И где тут «классический» вид x[j][k] ?

Нету. Есть operator() с верхним ограничением на количество индексов. А у тебя можно x[1][2][3][4][... и дальше сколько угодно раз для любого x который TMATRIX.

quasimoto ★★★★
()
Ответ на: комментарий от ilovewindows

нет.

  • совмещение malloc и new
  • вычисление размера памяти через sizeof(void*)
  • использование знакового типа для определения требуемой памяти
  • выделение памяти нулевого размера
  • отсутствие проверки результата выделения памяти
  • отсутствие проверки при обращении к выделенной памяти
  • отсутствие освобождения памяти
  • лишний val в массивах и лишний rows в элементах

выделение памяти нулевого размера:

#include <stdlib.h>
int main() { return (malloc(0))!=0; }
$ rm a.out;
$ gcc main.c -o a.out;
$ valgrind --leak-check=full ./a.out 2>&1 | grep ERROR
==3490== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)

anonymous
()
Ответ на: комментарий от anonymous

А в чем криминал совмещения malloc и new ? А в чем криминал вычисления размера указателя через void*, другой тип вернет какой-то другой размер ? А в чем криминал знакового типа для определения требуемой памяти, у меня 500 мегов оперативки, мне и int за глаза хватает. И где там память нулевого размера ? Ты книжки почитай, в любой книжке проверки убирают, чтобы мысль не терялась среди проверок. Освобождение памяти сам допишешь. val не лишний, а зарезервированный, row лишнего нет.

ilovewindows ★★★★★
()
Ответ на: комментарий от quasimoto

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

ilovewindows ★★★★★
()

Ну вообще есть можно так (если размерность не меняется):

int (*array)[nCollumns] = new int[nRows][nCollumns];
//Прототип функции:
void f(int (*a)[nCollumns]);
//Удаление
delete[] array;
rk17
()
Ответ на: комментарий от ilovewindows

Допиши проверку и запись в лог.

Писать тебе, причём в compile-time — у меня уже написано и работает.

Что характерно — указатели/массивы си и стандартные контейнеры C++ не позволят с ними так обращаться (многократно вызывать operator[]), и это compile-time гарантии.

Считай домашним заданием.

Как раз твой код недвусмысленно намекает на таковое — при трудоустройстве исправят, думаю, если ты такой Ъ, что всё «знаешь» («скорости роста производительности процессоров», ага, типа наплевательское отношение к иерархии памяти не сказывается всё больше и больше) и не слушаешь что тебе тут говорят.

quasimoto ★★★★
()
Ответ на: комментарий от Boy_from_Jungle

Лорчую, специально грепал за этим советом.
Только разве не typedef std::vector<std::vector<Type> > Array; ? (добавился пробел)
Уверен, что ОП экономит на спичках.

anonymous
()
Ответ на: комментарий от ilovewindows

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

#include <cassert>
#include <cstddef>
#include <initializer_list>

template <typename T>
class tensor {
public:

    typedef T value_type;
    typedef std::initializer_list<size_t> indexes;

private:

    size_t size;

    union {
        tensor *nested;
        T value;
    } data;

public:

    tensor() : size(0) {}

    tensor(indexes::iterator begin, indexes::iterator end) {
        if (begin == end)
            size = 0;
        else {
            size = *begin;
            data.nested = size ? new tensor[size] : 0;
            for (size_t i = 0; i < size; ++i)
                new (data.nested + i) tensor(begin + 1, end);
        }
    }

    tensor(indexes sizes) : tensor(sizes.begin(), sizes.end()) {}

    ~tensor() {
        if (size) delete [](data.nested);
    }

    tensor& operator[](size_t index) {
        assert(size);
        return data.nested[index];
    }

    T& operator()() {
        assert(!size);
        return data.value;
    }

};

/*
 t[a][b][c]()

 gcc:

	salq	$4, %rsi
	addq	8(%rdi), %rsi
	salq	$4, %rdx
	salq	$4, %rcx
	addq	8(%rsi), %rdx
	addq	8(%rdx), %rcx
	movq	8(%rcx), %rax

 clang:

	shlq	$4, %rsi
	movq	8(%rdi), %rax
	movq	8(%rax,%rsi), %rax
	shlq	$4, %rdx
	movq	8(%rax,%rdx), %rax
	shlq	$4, %rcx
	movq	8(%rax,%rcx), %rax
 */

#include <cstdio>
#include <iostream>

int main()
{
    size_t I, J, K;
    std::cin >> I >> J >> K;

    tensor<long> t{I, J, K};

    for(size_t i = 0; i < I; ++i)
        for(size_t j = 0; j < J; ++j)
            for(size_t k = 0; k < K; ++k)
                t[i][j][k]() = long(i * 100 + j * 10 + k);

    for(size_t i = 0; i < I; ++i)
        for(size_t j = 0; j < J; ++j)
            for(size_t k = 0; k < K; ++k)
                printf("t(%ld, %ld, %ld) = %ld (%p)\n",
                       i, j, k, t[i][j][k](), &t[i][j][k]());
}

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

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

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

ilovewindows ★★★★★
()
Ответ на: комментарий от quasimoto

Ну ты сам ответил как надо быстро - выделить кусок и вычислять индекс, желательно без операции умножения. А шаблоны, С++, красивые записи [x][y][z] это понты.

ilovewindows ★★★★★
()
Ответ на: комментарий от ilovewindows

А, ну извини :) Но твой пример всё равно запутанный — достаточно просто new[] один раз для TMATRIX *rows и placement new по кускам, мой другой пример тоже прост — static_product мог быть парой строчек for (с той же производительностью), но специально сделано через шаблонную рекурсию чтобы для недопустимого количества индексов она не компилировалась.

quasimoto ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.