Не передавайте массив как единственный указатель
Причина
Интерфейсы в стиле (указатель, размер) подвержены ошибкам. Кроме того, обычный указатель (на массив) должен опираться на некоторое соглашение, позволяющее вызываемой функции определить размер.
Пример
Рассмотрим:
void copy_n(const T* p, T* q, int n); // копировать из [p:p+n) в [q:q+n)
Что если в массиве, на который указывает q, меньше n элементов? Тогда мы перезаписываем, вероятно, несвязанную память. Что если в массиве, на который указывает p, меньше n элементов? Тогда мы читаем, вероятно, несвязанную память. И то, и другое является неопределённым поведением и потенциально очень неприятной ошибкой.
Альтернатива
Рассмотрите использование явных span:
void copy(span<const T> r, span<T> r2); // копировать r в r2
Пример (плохой)
Рассмотрим:
void draw(Shape* p, int n); // плохой интерфейс; плохой код
Circle arr[10];
// ...
draw(arr, 10);
Передача 10 в качестве аргумента n может быть ошибкой: наиболее распространённое соглашение — предполагать [0:n), но это нигде не указано. Хуже того, что вызов draw() вообще скомпилировался: было неявное преобразование из массива в указатель (деградация массива), а затем ещё одно неявное преобразование из Circle в Shape. Нет никакого способа, при котором draw() могла бы безопасно итерироваться по этому массиву: у неё нет способа узнать размер элементов.
Альтернатива: Используйте вспомогательный класс, гарантирующий правильное количество элементов и предотвращающий опасные неявные преобразования. Например:
void draw2(span<Circle>);
Circle arr[10];
// ...
draw2(span<Circle>(arr)); // вывести количество элементов
draw2(arr); // вывести тип элемента и размер массива
void draw3(span<Shape>);
draw3(arr); // ошибка: нельзя преобразовать Circle[10] в span<Shape>
Эта draw2() передаёт в draw() то же количество информации, но делает явным тот факт, что это должен быть диапазон Circle. Смотрите ???.
Исключение
Используйте zstring и czstring для представления C-строк с завершающим нулём. Но при этом используйте std::string_view или span<char> из GSL для предотвращения ошибок диапазона.
Контроль
- (Простой) ((Границы)) Предупреждать о любом выражении, которое будет опираться на неявное преобразование типа массива в тип указателя. Допускать исключения для типов указателей zstring/czstring.
- (Простой) ((Границы)) Предупреждать о любой арифметической операции с выражением типа указателя, дающей значение типа указателя. Допускать исключения для типов указателей zstring/czstring.