Используя чтение () непосредственно в C++ std:vector

Я оборачиваю пространство пользователя функциональность сокета Linux в некотором C++ для встроенной системы (да, это, вероятно, изобретает велосипед снова).

Я хочу предложить чтение и реализацию записи с помощью вектора.

Выполнение записи довольно легко, я могу просто передать &myvec[0] и избегайте ненужного копирования. Я хотел бы сделать то же и читать непосредственно в вектор, вместо того, чтобы читать в символьный буфер, затем копируя все это в недавно созданный вектор.

Теперь, я знаю, сколько данных я хочу считать, и я могу выделить соответственно (vec.reserve()). Я могу также читать в &myvec[0], хотя это - вероятно, ОЧЕНЬ ПЛОХАЯ ИДЕЯ. Очевидно, выполнение этого не позволяет myvec.size возвращать что-либо разумное. Есть ли любой способ сделать это что:

  1. Не полностью чувствует yucky с точки зрения безопасности/C++
  2. Не включает две копии блока данных - однажды от ядра до пространства пользователя и однажды от C char * разработайте буфер в вектор C++.
17
задан unwind 6 May 2010 в 11:12
поделиться

4 ответа

Используйте resize() вместо reserve(). Это правильно установит размер вектора -- и после этого &myvec[0], как обычно, гарантированно будет указывать на непрерывный блок памяти.

Правка: Использование &myvec[0] в качестве указателя на базовый массив как для чтения, так и для записи безопасно и гарантировано стандартом C++. Вот что говорит Херб Саттер по этому поводу:

Так почему же люди постоянно спрашивают, хранятся ли элементы std::vector (или std::array) смежно? Наиболее вероятной причиной является то, что они хотят знать, могут ли они получить указатели на внутренние элементы, чтобы поделиться данными, либо для чтения, либо для записи, с другим кодом, который работает с массивами C. Это правильное использование, и оно достаточно важно, чтобы гарантировать его в стандарте.

24
ответ дан 30 November 2019 в 12:50
поделиться

Я просто добавлю короткое пояснение, потому что ответ уже был дан. resize () с аргументом больше текущего размера добавит элементы в коллекцию, а по умолчанию - инициализирует их. Если вы создадите

std::vector<unsigned char> v;

, а затем измените размер

v.resize(someSize);

, все символы без знака будут инициализированы до 0. Кстати, вы можете сделать то же самое с конструктором

std::vector<unsigned char> v(someSize);

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

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

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

2
ответ дан 30 November 2019 в 12:50
поделиться

Предполагая, что это структура POD, вызовите resize , а не резерв . Вы можете определить пустой конструктор по умолчанию, если вы действительно не хотите, чтобы данные обнулялись перед заполнением вектора.

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

РЕДАКТИРОВАТЬ: ах, байты, а не структура. Что ж, вы можете использовать тот же трюк и определить структуру с помощью только char и конструктора по умолчанию, который не инициализирует его ... если я правильно предполагаю, что вас это волнует, и поэтому вы хотели вызвать зарезервировать вместо изменить размер в первую очередь.

1
ответ дан 30 November 2019 в 12:50
поделиться

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

Первый resize () обнулит элементы вектора, но это вряд ли приведет к значительному снижению производительности. Если да, то вы можете попробовать предложение Potatoswatter или отказаться от размера вектора, отражающего размер считываемых данных, и вместо этого просто resize () его один раз, а затем точно использовать повторно как выделенный буфер в C.

С точки зрения производительности, если вы читаете из сокета в пользовательском режиме, скорее всего, вы сможете легко обрабатывать данные так же быстро, как они поступают. Может быть, нет, если вы подключаетесь к другой компьютер в гигабитной локальной сети, или если на вашем компьютере часто используется 100% ЦП или 100% пропускная способность памяти. Немного дополнительного копирования или настройки памяти не представляет большого труда, если вы все равно собираетесь заблокировать вызов read .

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

1
ответ дан 30 November 2019 в 12:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: