Должен ли я заменить (void*, size) на диапазон GSL?
Предположим, у меня есть
int foo(void* p, size_t size_in_bytes);
и предположить, что не имеет смысла делать foo
набран. Я хочу быть хорошим программистом и применять основные принципы C++. В частности, я хочу использовать span вместо пар (*, len). Что ж, span<void>
не скомпилируется (не может добавить к void *
); а также span<char>
или же span<uint8_t>
и т. д. подразумевает, что foo ожидает символы, а это не так.
Так что я должен использовать span<something-with-size-1>
в этом случае, или придерживаться void*
?
3 ответа
То, что я решил сделать, и что я думаю, скажем так, с точки зрения дизайна звука, это реализовать класс с именем memory_region
, который имеет все функции, не зависящие от типа gsl::span
(следовательно, например, он не имеет начала () или конца ()). Это не то же самое, что диапазон байтов, IMO - и я не могу их запутать конструктивно.
Вот моя реализация (это часть репозитория ядер GPU, связанных с СУБД, и инфраструктуры тестирования, над которой я работаю, отсюда и фрагмент, связанный с CUDA; и это зависит от некоторого GSL, в моем случае gsl-lite от MS'es должен я тоже буду в порядке).
На этот вопрос не может быть общего ответа.
Для функции, чтобы сказать, что требуется span<T>
означает, что он принимает непрерывный массив значений, без какой-либо формы передачи права собственности. Если это описание не отражает разумно происходящее, тогда оно не должно span<T>
,
Например:
Что если функция проверяет, пересекает ли буфер область в моей области памяти, которая, скажем, сопоставлена с файлом?
Это не похоже на span<T>
, Похоже, у вас должен быть простой агрегат с именем, которое прояснит, что это значит:
struct memory_region
{
void* p;
size_t size_in_bytes;
};
Вы могли бы даже дать ему функцию-член для тестирования пересечений. Если вы создаете систему для работы с такими областями памяти, я мог бы посоветовать более инкапсулированный тип класса с конструкторами и тому подобное.
Какой тип использует функция, следует объяснить, что означают данные. Предпочтительно, чтобы это значение было в общем смысле, но, по крайней мере, в нем должно быть указано, что оно означает для рассматриваемой функции.
Еще кое-что:
или же
span<uint8_t>
и т.д. будет означать, что Foo действительно ожидает символов
Нет, не будет. В то время как uint8_t
почти наверняка будет иметь такой же размер, как unsigned char
, это не означает, что можно было бы ожидать, чтобы иметь возможность передавать массив символов в любую функцию, которая принимает span<uint8_t>
, Если бы эта функция хотела объявить, что она принимает символы, она бы использовала unsigned char
,
Я хотел сказать
span<whatever>
будет означать функцию ожидатьwhatever
"S.
Да, требование для span
s в том, что передается фактический массив T
с данного размера.
Комитет по стандартизации C++ предлагает следующее: если вы хотите передать указатель на последовательность байтов (что часто и делают люди, передавая void*
вокруг), то вы бы передать span<std::byte>
, который опирается на новый std::byte
тип. Однако это требует небольшого изменения языкового стандарта, чтобы быть законным.
В сегодняшнем C++ вы могли бы пройти span<unsigned char>
(введите dedef, как вы считаете наиболее описательным) и получите тот же эффект: доступ к последовательности байтов.