Здравствуйте, qaz77, Вы писали:
Q>Не совсем понятно, как можно собрать большой вектор байтов (пакет) из нескольких маленьких векторов байт путем перемещения и без копирования. Q>По моему, концепция непрерывного блока памяти в векторе убивает такую идею на корню.
У меня изначально создается нужного размера вектор в конструкторе, частично заполняю данными. Но для удобства часть данных вносятся позже через сеттеры. Там где нужно сделать преобразование бинарных данных — доступ через span без выделения памяти.
Q>Ну если там части пакета это условные uint32_t, то может и норм.
Часть мелких — типа timestamp или noise. Но так же и доступ через span без выделения памяти.
Здравствуйте, Shmj, Вы писали:
S>Здравствуйте, _NN_, Вы писали:
S>>>Но еще есть вопрос наглядности — а это тоже важно. Чтобы получать нужную часть пакета — одной удобной строчкой с внятным названием — т.е. чтобы вся магия манипуляции с байтами — была не видна при взаимодействии. _NN>>Секунду, вам нужна часть вектора или весь ? _NN>>Невозможно забрать только часть без копирования.
S>Части вектора в виде span — беру пока объект живой и владеет вектором — для удобства. Можно было бы все те же операции проделать до создания объекта — но это не нагладно было бы и не дешевле по ресурсам.
Всё хорошо, возвращаем span и не копируем лишний раз.
Только это не связано с тем, что в C++ называется перемещением.
Здравствуйте, _NN_, Вы писали:
S>>Части вектора в виде span — беру пока объект живой и владеет вектором — для удобства. Можно было бы все те же операции проделать до создания объекта — но это не нагладно было бы и не дешевле по ресурсам. _NN>Всё хорошо, возвращаем span и не копируем лишний раз. _NN>Только это не связано с тем, что в C++ называется перемещением.
Перемещение уже производим в самом конце — когда пакет сформирован. Берем у этого класса-пакета байты вектора и конфискуем — передаем далее (в другую обертку).
Здравствуйте, Shmj, Вы писали:
S>Я так и сделал — класс овладевает вектором, получаю нужные элементы вектора с помощью span и примитивных типов. Потом отнимаю владение, дабы не копировать, передаю в другую обертку — и уже эту обертку на выход.
Да вот в том-то и дело, что это нифига не так. Ты, походу, вообще нифига не понял, из того, что я тебе писал.
Тебе здесь уже сто раз могли бы помочь, если бы ты сразу рассказал о конкретной задаче, а не пускался в философию программирования с абстрактными примерами.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Shmj, Вы писали:
S>Просто вы тут любите так написать, чтобы 4-х этажные шаблоны с FINAE, чтоб без поллитра не разобраться. А когда кто-то пишет максимально просто и понятно — считается по-лоховски.
Глупый, шаблоны — это средство, а не самоцель. Никто не станет писать шаблоны просто ради шаблонов. Лично я на любой случай использования шаблона могу детально пояснить, для чего и почему.
Если ли же говорить о твоём конкретном случае, то у тебя просто всё через жопу и дело тут вовсе не в шаблонах. И, как я писал уже, тебе уже сто раз могли бы помочь, если бы ты сразу рассказал о решаемой задаче, а не пускался в философию программирования с абстрактными примерами.
Кроме того, ты совершенно правильно заметил, что "многоэтажность" была характерна для старых версий языка и SFINAE. Сейчас вместо этого используются концепты и улучшенный синтаксис. Сейчас в большинстве случаев можно даже традиционную шаблонную шапку не писать. Я думаю, лопух типа тебя даже не всегда отличит шаблонную функцию от нешаблонной.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Shmj, Вы писали:
S>Перемещение уже производим в самом конце — когда пакет сформирован. Берем у этого класса-пакета байты вектора и конфискуем — передаем далее (в другую обертку).
Во-первых, не у класса, а у объекта класса. Во всём и везеде у тебя нечёткость и, как следствие, сплошная путаница. Срала-мазала.
Во-вторых, а нафига было отдавать этот вектор какому-то объекту класса, если потом всё равно забирать? Смотри, что получается, на входе у тебя какие-то входные данные для создания пакета, на выходе — вектор байт. То есть, это простая функция без побочных эффектов с чётким входом и выходом. На кой хер, спрашивается, ты превращаешь это в машину состояний? Потому что в сишарп всё на классах?
То же самое и про "другую обертку". Ты не замечаешь, что у тебя обёртки ради обёрток? У тебя же вектор — это не какая-то там деталь реализации, которую нужно инкапсулировать — вектор у тебя находится прямо в модели данных самого верхнего уровня. На кой хер ты его пхнёшь в какие-то промежуточные обёртки, то "овладевая", то "отбирая"? Что за свингер-пати ты устроил?
Завязывал бы ты со своей трепологией и занялся бы делом, наконец.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, Shmj, Вы писали:
S>Здравствуйте, _NN_, Вы писали:
S>>>Части вектора в виде span — беру пока объект живой и владеет вектором — для удобства. Можно было бы все те же операции проделать до создания объекта — но это не нагладно было бы и не дешевле по ресурсам. _NN>>Всё хорошо, возвращаем span и не копируем лишний раз. _NN>>Только это не связано с тем, что в C++ называется перемещением.
S>Перемещение уже производим в самом конце — когда пакет сформирован. Берем у этого класса-пакета байты вектора и конфискуем — передаем далее (в другую обертку).
Перемещение чего ? вектора, который мы держив внутри ?
Вроде такого ?
using namespace std;
class Packet
{
public:
vector<byte>&& release_vector() { return move(bytes); }
span<byte> get_writable_range(size_t from, size_t to)
{
// Ensure size is at least `to`.if (to > bytes.size()) {
bytes.resize(to);
}
return { &bytes[from], &bytes[to] };
}
private:
vector<byte> bytes;
};
Packet p;
auto part1 = p.get_writable_range(1,10);
.. work with part 1
auto part2 = p.get_writable_range(10,20);
.. work with part 2
// Steal ownership
vector<byte> result = p.release_vector();
// work with result
В таком варианте неясно зачем нужно вытаскивать вектор, и не работать просто с объектом Packet.
Здравствуйте, Shmj, Вы писали:
S>У меня изначально создается нужного размера вектор в конструкторе, частично заполняю данными. Но для удобства часть данных вносятся позже через сеттеры. Там где нужно сделать преобразование бинарных данных — доступ через span без выделения памяти.
Я к тому, что если есть два относительно больших вектора, то слить их в один другой вектор без копирования не получится никак.
Перемещение здесь ничем не поможет.
Я сам делал нечто подобное много лет назад, с бинарными сетевыми пакетами.
Там у меня были большие данные и маленький заголовок пакета фиксированного размера.
Если данные формируются где-то на стороне, то выдаем этой стороне вектор с зарезервированным местом для заголовка, а потом перемещаем себе и формируем заголовок.
Когда move-семантики не было, то это через swap делалось, но суть та же.
Здравствуйте, _NN_, Вы писали:
_NN>В таком варианте неясно зачем нужно вытаскивать вектор, и не работать просто с объектом Packet.
Это не первый его пост в таком духе. Он никогда не рассматривает вариант, что в его решении что-то может быть не совсем идеально, поэтом сразу переходит к обсуждению глобальных проблем С++ на абстрактных примерах.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>Здравствуйте, _NN_, Вы писали:
_NN>>В таком варианте неясно зачем нужно вытаскивать вектор, и не работать просто с объектом Packet.
R>Это не первый его пост в таком духе. Он никогда не рассматривает вариант, что в его решении что-то может быть не совсем идеально, поэтом сразу переходит к обсуждению глобальных проблем С++ на абстрактных примерах.
Ну подождём ответа на конкретный вопрос
Как я писал выше, для работы с бинарными данными вообще ничего не нужно писать, а генерировать через Kaitai Struct.
Мало того, что сразу получаем код для всех языков, так и ещё всё описано декларативно.
Здравствуйте, rg45, Вы писали:
R>Во-вторых, а нафига было отдавать этот вектор какому-то объекту класса, если потом всё равно забирать?
Только лишь по одной причине — мы люди и нам удобнее код разбивать на функции, удобнее манипулировать объектами — так легче управлять.
Если бы не наша человечность и свойственные нашей психике паттерны восприятия — то не нужно было бы разбивать код на множество функций и создавать объекты — все бы писалось одним большим куском в машинных кодах.
R>Смотри, что получается, на входе у тебя какие-то входные данные для создания пакета, на выходе — вектор байт. То есть, это простая функция без побочных эффектов с чётким входом и выходом.
Это можно было бы оформить в виде функции — но так не удобно. Т.е. типа передаем вектор в функцию, эта функция последовательно устанавливает части вектора, основываясь на неких индексах. Но так не наглядно — все индексы перенесены в класс-обертку а функция просто получает части этого пакета у удобном виде по названию, не думая об индексах и смещениях.
R>На кой хер, спрашивается, ты превращаешь это в машину состояний? Потому что в сишарп всё на классах?
Тут нет машины состояний — по прежнему просто доступ к частям массива, просто удобным образом.
R>То же самое и про "другую обертку". Ты не замечаешь, что у тебя обёртки ради обёрток?
А как же. Это для удобства восприятия. Как и разбиение на функции — можно было бы не разбивать, все писать в одной большой функции — зачем плодить, если можно в одной?
R>У тебя же вектор — это не какая-то там деталь реализации, которую нужно инкапсулировать — вектор у тебя находится прямо в модели данных самого верхнего уровня. На кой хер ты его пхнёшь в какие-то промежуточные обёртки, то "овладевая", то "отбирая"? Что за свингер-пати ты устроил?
Чтобы было наглядно и удобно — не работать с индексами а лишь получать удобно читаемые названия.
S>Перемещение уже производим в самом конце — когда пакет сформирован. Берем у этого класса-пакета байты вектора и конфискуем — передаем далее (в другую обертку).
Если ты возвращаешь/передаешь вектор — там, скорее всего тоже будет перемещение, компилятор всё за тебя сделает. Ты упёрся в один не самый главный аспект, а в остальном наколбасил кучу говна
Здравствуйте, Shmj, Вы писали:
S>Здравствуйте, _NN_, Вы писали:
_NN>>В таком варианте неясно зачем нужно вытаскивать вектор, и не работать просто с объектом Packet.
S>Там получается есть тело — у него один формат. А есть общий пакет. Так вот это тело формируем и передаем уже далее, в обертку общего пакета.
Ничего не понятно, что это означает.
Вы код покажите.
А то неясно это вот так:
"Есть один формат:"
class Body { vector<bytes> b; };
"Есть общий пакет:"
class Packet { vector<bytes> b; };
Body b;
Packet p;
p.b.insert(p.begin(), b.begin(), b.end()); // copy
В таком варианте придётся копировать данные из Body в Packet.
Или так?
"Есть один формат:"
class Body { span<bytes> b; };
"Есть общий пакет:"
class Packet { vector<bytes> b; };
Packet p;
Body b = span(p.b.begin(), p.b.begin() + 10);
Здравствуйте, Shmj, Вы писали:
S>Только лишь по одной причине — мы люди и нам удобнее код разбивать на функции, удобнее манипулировать объектами — так легче управлять. S>Если бы не наша человечность и свойственные нашей психике паттерны восприятия — то не нужно было бы разбивать код на множество функций и создавать объекты — все бы писалось одним большим куском в машинных кодах. S>Это можно было бы оформить в виде функции — но так не удобно. Т.е. типа передаем вектор в функцию, эта функция последовательно устанавливает части вектора, основываясь на неких индексах. Но так не наглядно — все индексы перенесены в класс-обертку а функция просто получает части этого пакета у удобном виде по названию, не думая об индексах и смещениях. S>Тут нет машины состояний — по прежнему просто доступ к частям массива, просто удобным образом. S>А как же. Это для удобства восприятия. Как и разбиение на функции — можно было бы не разбивать, все писать в одной большой функции — зачем плодить, если можно в одной? S>Чтобы было наглядно и удобно — не работать с индексами а лишь получать удобно читаемые названия.
Перевожу на человеческий язык: "Мой код идеален, в нём нет недостатков. А в том, что получается говно, виноват С++, потому что он не C#".
--
Справедливость выше закона. А человечность выше справедливости.
— работаем с _packetBytes. А вот _storage может быть как внешним (тогда в классе он не установлен), так и внутренним — в зависимости генерим пакет или парсим.
Но вы зрите в корень, возможно еще вернусь к этому.