Преобразование (void*) в std::vector‹unsigned char›

У меня есть буфер (void*), который мне нужно преобразовать в std::vector<unsigned char>, прежде чем я смогу его передать. К сожалению, мои навыки приведения C++ немного слабы. Какие-либо предложения?


person Mike Douglas    schedule 07.04.2009    source источник


Ответы (4)


Вам понадобится длина буфера. Как только вы это сделаете, мы можем сделать это:

unsigned char *charBuf = (unsigned char*)voidBuf;
/* create a vector by copying out the contents of charBuf */
std::vector<unsigned char> v(charBuf, charBuf + len);

Хорошо, комментарий заставил меня задуматься, почему я не использовал reinterpret_cast:

  • В C++ приведение в стиле C является удобной функцией — она просит компилятор выбрать наиболее безопасную и переносимую форму преобразования из набора доступных операторов приведения.

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

  • Преобразование между (unsigned не меняет тип) char * и void * является переносимым (на самом деле вы можете использовать static_cast, если вы действительно разборчивы).

Проблема с приведением в стиле C заключается в следующем: добавленная гибкость может вызвать сердечные боли при изменении типа указателя.

Примечание. Я согласен с общим правилом не проводить кастинг как можно чаще. Однако, без указания источника, это лучшее, что я мог сделать.

person dirkgently    schedule 07.04.2009
comment
reinterpret_cast легче найти. - person Thomas L Holaday; 07.04.2009
comment
@tlholaday: static_cast‹› можно использовать для приведения к void*, поэтому его следует использовать вместо этого. - person j_random_hacker; 07.04.2009
comment
@dirkgently: +1, но, пожалуйста, укажите, что это создает копию буфера - это важно, но не очевидно из вашего поста. - person j_random_hacker; 07.04.2009
comment
@j_random_hacker: OP упомянул «прохождение» - я предположил, что он имел в виду копию. Во всяком случае, обновленный источник с комментариями. - person dirkgently; 07.04.2009
comment
да, если что, почему бы и не static_cast‹›. он не определен, он переносим. это просто не удобно. но это намного безопаснее :) в любом случае, вы объяснили, почему вы использовали приведение в стиле c. нравится, так что +1 :D - person Johannes Schaub - litb; 07.04.2009
comment
тем не менее, я на самом деле думаю, что приведение из void * к любому указателю объекта является неопределенным поведением, когда оно выполняется с помощью reinterpret_cast. стандарт говорит, что можно выполнять приведение между двумя указателями, имеющими тип указатель-объект. но void* является указателем на пустоту. хотя я думаю, что это необычная интерпретация - person Johannes Schaub - litb; 07.04.2009
comment
@litb: IIRC, найдите раздел о безопасно полученных значениях указателя. В этом разделе может быть ответ. - person dirkgently; 07.04.2009
comment
я посмотрю на ревизии С++ 03. я не могу найти ничего в С++ 98, что позволяет это. но плохо скажу вам, если я найду его. ваше здоровье :) - person Johannes Schaub - litb; 07.04.2009
comment
@litb: я имел в виду поиск черновиков C++0x. Будет продолжать смотреть. - person dirkgently; 07.04.2009

Вы не можете просто привести void* к std::vector<unsigned char>, потому что расположение памяти последнего включает другие объекты, такие как размер и количество байтов, выделенных в данный момент.

Предположим, что на буфер указывает buf, а его длина равна n:

vector<unsigned char> vuc(static_cast<char*>(buf), static_cast<char*>(buf) + n);

создаст копию буфера, которую можно безопасно использовать.

[EDIT: добавлено static_cast<char*>, необходимое для арифметики указателей.]

person j_random_hacker    schedule 07.04.2009

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

void SomeFunc(void* input);

main() {
  std::vector< unsigned char > v;
  SomeFunc((void*) &v);
}

SomeFunc(void* input) {
  // Now, you could cast that void* into a vector
  std::vector< unsigned char >* v_ = (vector<unsigned char>*)input
}

На самом деле я не пытался посмотреть, будет ли это работать, но в этом суть. Тем не менее, если вы делаете это с нуля, вы определенно делаете это неправильно. Это действительно плохо. Единственный раз, когда это может быть даже отдаленно понятно, - это если вы вынуждены реализовать уже определенную "SomeFunc()".

person teeks99    schedule 07.04.2009

использование класса std::vector для уже выделенного буфера не является решением. Объект std::vector управляет памятью и освобождает ее во время уничтожения.

Сложное решение может состоять в том, чтобы написать свой собственный распределитель, который использует уже выделенный буфер, но вы должны быть очень осторожны в нескольких сценариях, таких как изменение размера вектора и т. д.

Если у вас есть этот буфер void*, связанный с некоторыми функциями C API, вы можете забыть о преобразовании в std::vector.

Если вам нужна только копия этого буфера, это можно сделать так:

std::vector< unsigned char> cpy( 
    (unsigned char*)buffer, (unsigned char*)buffer + bufferSize);

где bufferSize — размер копируемого буфера в символах.

person Cătălin Pitiș    schedule 07.04.2009