LINUX.ORG.RU

История изменений

Исправление quasimoto, (текущая версия) :

#include <array>
#include <cstdio>

template <typename T, size_t h, size_t w>
using Matrix = std::array<std::array<T, w>, h>;

struct Something {
    bool property;
    int value;
    Something() : property(true) {}
};

template <size_t h, size_t w>
void doSomething(Matrix<Something, h, w>& mx)
{
    int x = 0;
    for (auto& col : mx)
        for (auto& el : col) {
            printf("%p\n", &el);
            el.value = ++x;
        }
}

int main()
{
    printf("sizeof cell = %ld\n", sizeof(Something));

    constexpr size_t h = 3, w = 3;

    Matrix<Something, h, w> mx;
    // movb	$1, (%rsp)
    // movb	$1, 8(%rsp)
    // movb	$1, 16(%rsp)
    // movb	$1, 24(%rsp)
    // movb	$1, 32(%rsp)
    // movb	$1, 40(%rsp)
    // movb	$1, 48(%rsp)
    // movb	$1, 56(%rsp)
    // movb	$1, 64(%rsp)

    doSomething(mx);

    for (size_t i = 0; i < h; ++i) {
        printf("{ ");
        for (size_t j = 0; j < w; ++j)
            printf("(%p){%d %d} ", &mx[i][j], mx[i][j].property, mx[i][j].value);
        puts("}");
    }
}

/*

sizeof cell = 8
0x7ff0000d8
0x7ff0000e0
0x7ff0000e8
0x7ff0000f0
0x7ff0000f8
0x7ff000100
0x7ff000108
0x7ff000110
0x7ff000118
{ (0x7ff0000d8){1 1} (0x7ff0000e0){1 2} (0x7ff0000e8){1 3} }
{ (0x7ff0000f0){1 4} (0x7ff0000f8){1 5} (0x7ff000100){1 6} }
{ (0x7ff000108){1 7} (0x7ff000110){1 8} (0x7ff000118){1 9} }

 */

/*

  total heap usage: 0 allocs, 0 frees, 0 bytes allocated

 */

Обрати внимание на 0 аллокаций в куче, на код аллокации на стеке, на дефолтный конструктор, на два способа обхода и на непрерывный layout элементов матрицы в памяти.

Если h и w неизвестны на момент компиляции, то нужно делать как предложил tailgunner, то есть писать свой класс с аллокацией одним куском и доступом с помощью арифметики i * w + j индексов. На самом деле (по стандарту), для статических T[h][w] и std::array<std::array<T, w>, h> компилятор сам располагает их непрерывно в памяти и пишет ту же самую арифметику для индексов в ассемблер для [ i ][j].

Исходная версия quasimoto, :

#include <array>
#include <cstdio>

template <typename T, size_t h, size_t w>
using Matrix = std::array<std::array<T, w>, h>;

struct Something {
    bool property;
    int value;
    Something() : property(true) {}
};

template <size_t h, size_t w>
void doSomething(Matrix<Something, h, w>& mx)
{
    int x = 0;
    for (auto& col : mx)
        for (auto& el : col) {
            printf("%p\n", &el);
            el.value = ++x;
        }
}

int main()
{
    printf("sizeof cell = %ld\n", sizeof(Something));

    constexpr size_t h = 3, w = 3;

    Matrix<Something, h, w> mx;
    // movb	$1, (%rsp)
    // movb	$1, 8(%rsp)
    // movb	$1, 16(%rsp)
    // movb	$1, 24(%rsp)
    // movb	$1, 32(%rsp)
    // movb	$1, 40(%rsp)
    // movb	$1, 48(%rsp)
    // movb	$1, 56(%rsp)
    // movb	$1, 64(%rsp)

    doSomething(mx);

    for (size_t i = 0; i < h; ++i) {
        printf("{ ");
        for (size_t j = 0; j < w; ++j)
            printf("(%p){%d %d} ", &mx[i][j], mx[i][j].property, mx[i][j].value);
        puts("}");
    }
}

/*

sizeof cell = 8
0x7ff0000d8
0x7ff0000e0
0x7ff0000e8
0x7ff0000f0
0x7ff0000f8
0x7ff000100
0x7ff000108
0x7ff000110
0x7ff000118
{ (0x7ff0000d8){1 1} (0x7ff0000e0){1 2} (0x7ff0000e8){1 3} }
{ (0x7ff0000f0){1 4} (0x7ff0000f8){1 5} (0x7ff000100){1 6} }
{ (0x7ff000108){1 7} (0x7ff000110){1 8} (0x7ff000118){1 9} }

 */

/*

  total heap usage: 0 allocs, 0 frees, 0 bytes allocated

 */

Обрати внимание на 0 аллокаций в куче, на код аллокации на стеке, на дефолтный конструктор, на два способа обхода и на непрерывный layout элементов матрицы в памяти.

Если h и w неизвестны на момент компиляции, то нужно делать как предложил tailgunner, то есть писать свой класс с аллокацией одним куском и доступом с помощью арифметики i * w + j индексов. На самом деле (по стандарту), для статических T[h][w] и std::array<std::array<T, w>, h> компилятор сам располагает их непрерывно в памяти и пишет ту же самую арифметику для индексов в ассемблер для [j].