Практика кодирования - поплавок* -> метода Vector3* литая


Если вы были поставлены следующие:

#include <cassert>

struct vec {
    float x,y,z;
    vec(float x, float y, float z) : x(x), y(y), z(z) {}
};

int main() {
    float verts[] = {1,2,3,4,5,6,7,8,9}; // length guaranteed to be a multiple of 3
    assert(sizeof(vec) == sizeof(float) * 3);

    // Option 1
    for (int i = 0; i < 3; ++i) {
        auto a = reinterpret_cast<vec*>(verts)[i];
        // ...
    }

    // Option 2
    for (int i = 0; i < 9; i += 3) {
        vec a(verts[i], verts[i+1], verts[i+2]); // -O3 averts the copy, so d/w
        // ...
    }

    return 0;
}

Что является лучшей практике?

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



585
4
задан 25 августа 2011 в 01:08 Источник Поделиться
Комментарии
4 ответа

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

struct vec {
float x,y,z;
vec(float fv[]) : x(fv[0]), y(fv[1]), z(fv[2]) {}
};

int main() {
float verts[] = {1,2,3,4,5,6,7,8,9};

for (int i = 0; i < 9; i += 3) {
const vec a(&verts[i]);
// ...
}

return 0;
}

3
ответ дан 25 августа 2011 в 09:08 Источник Поделиться

Я решительно предпочитаю вариант 3.

Варианты 1 и 2 напоминают мне большинство из K&R С, где указатель-это указатель на указатель. Если один из типов, то компилятор может не заметить, а это может привести к ошибкам, которые могут быть трудно найти.

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

1
ответ дан 25 августа 2011 в 03:08 Источник Поделиться

Почему бы не сделать это:

struct vec
{
float x,y,z;
};

int main()
{
vec verts[] = {{1,2,3}, {4,5,6}, {7,8,9}};

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

// Option 4
for (int i = 0; i < 3; ++i)
{
const vec& a = verts[i];

}

При написании кода C++, вы не должны использовать C литой оператора. C++ имеет четыре собственных, которые вы можете использовать:

const_cast           // If you need this you are either very clever or your design is wrong
reinterpret_cast // This is an indication that you are doing something non portable.
static_cast // This is a good cast (but any explicit cast is bad)
dynamic_cast // This casts up and down the class hierarchy (usually just down)

// Note: dynamic_cast is a runtime operation.
// all others are compile time casts.
// static_cast/dynamic_cast will actually generate compile
// time errors if you do something wrong very wrong. dynamic_cast
// can also throw an exception (or return NULL).

В вашем случае, когда я преобразовать ваш c-бросает в C++

   // option 1
const vec& a = reinterpret_cast<vec&>(verts[i]);

// Option 2
const vec& a = reinterpret_cast<vec*>(verts)[i];

Теперь, если вы представите свой код на C++ разработчиком первое, что они сделать, это спросить: зачем вам оператора reinterpret_cast? Это плохая идея.

1
ответ дан 25 августа 2011 в 04:08 Источник Поделиться

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

0
ответ дан 25 августа 2011 в 03:08 Источник Поделиться