Правильно ли я использую семантику перемещения? Какая будет выгода?
Интересно, если я использую move
семантически правильно:
class Vertex{
protected:
Common::Point3D position;
Common::Point3D normal;
Common::Point2D uv;
Common::Point2D tangent;
public:
Vertex(Common::Point3D &&position, Common::Point3D &&normal, Common::Point2D &&uv, Common::Point2D &&tangent)
: position(std::move(position)), normal(std::move(normal)), uv(std::move(uv)), tangent(std::move(tangent)){}
};
Чего я добьюсь здесь move
? Код для сравнения (я мог const &
тоже):
class Vertex{
protected:
Common::Point3D position;
Common::Point3D normal;
Common::Point2D uv;
Common::Point2D tangent;
public:
Vertex(Common::Point3D position, Common::Point3D normal, Common::Point2D uv, Common::Point2D tangent)
: position(position), normal(normal), uv(uv), tangent(tangent){}
};
Сколько копий будет предотвращено и какие из них произойдут в любом случае?
Я хотел бы использовать такой код:
Vertex * vertices = new Vertex[10000];
vertices[0] = Vertex(Common::Point3D(1,2,3), Common::Point3D(4,5,6)...);
vertices[1] = ...
Могу ли я оптимизировать это дальше?
1 ответ
Интересно, правильно ли я использую семантику перемещения:
Принимая только ссылку на rvalue, вы ограничиваете передачу lvalue этому конструктору. Вы, вероятно, довольно быстро узнаете, что не можете использовать это так, как ожидаете. Если вы принимаете типы по значению...
Vertex(Common::Point3D position, Common::Point3D normal, Common::Point2D uv, Common::Point2D tangent)
: position{std::move(position)}
, normal{std::move(normal)}
, uv{std::move(uv)}
, tangent{std::move(tangent)}
{}
... вы позволяете пользователю класса move
или же copy
в переменную конструктора, а затем вы всегда move
в вашу переменную-член. Это означает, что вы всегда будете вызывать 1 копию и 1 ход или 2 хода в зависимости от того, как вызывался ctor. В качестве альтернативы вы можете взять const&
и всегда вызывать ровно 1 копию, несмотря ни на что. Если вы хотите быть, несомненно, самый быстрый вы бы перегрузки для каждой комбинации &&
а также const&
, но это слишком много кода.
Чего я добьюсь здесь с ходом?
Делая предположение, что Point3D
содержит всего 3 ints / float / doubles, вы ничего не получите. Фундаментальные типы ничего не получают от move
Это так же, как копия.
Самым большим преимуществом перемещения является то, что вы можете "украсть" динамически выделенную память. Думать о vector
он динамически распределяет массив и содержит указатель на него. Когда ты move
он может просто скопировать этот указатель на новый объект и обнулить исходный указатель. Когда вы копируете его, он выделяет новую память в новом объекте и копирует массив (возможно, элемент за элементом) в новый массив. Большая разница в стоимости: выделение и копирование элементов массива по сравнению с простым копированием указателя.
Вывод: для ваших типов, проходя мимо const&
скорее всего, самый быстрый путь.