Должен ли я заменить (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.

Да, требование для spans в том, что передается фактический массив Tс данного размера.

Комитет по стандартизации C++ предлагает следующее: если вы хотите передать указатель на последовательность байтов (что часто и делают люди, передавая void* вокруг), то вы бы передать span<std::byte>, который опирается на новый std::byte тип. Однако это требует небольшого изменения языкового стандарта, чтобы быть законным.

В сегодняшнем C++ вы могли бы пройти span<unsigned char> (введите dedef, как вы считаете наиболее описательным) и получите тот же эффект: доступ к последовательности байтов.

Другие вопросы по тегам