Вы можете просто абстрагироваться от типа элементов .Все, что нужно вашему массиву, это знать, насколько велики эти элементы.Вы можете полностью разрешить пользователю предоставлять конструктор и деструктор копирования с помощью указателей на функции, или вы можете ограничить область действия вашего массива memcpy()
подвижными типами.
Предоставление массива для простых элементов данных
Вы просто добавляете размер элементов в качестве параметра к вашему массиву struct
:
typedef struct {
char *array;
size_t elementSize;
size_t used;
size_t size;
} Array;
void Array_init(Array *a, size_t elementSize, size_t initialSize);
void Array_insert(Array *a, const void* element);
const void* Array_at(Array *a, size_t index);
void Array_destruct(Array *a);
Вся индексация в массиве просто умножает индекс на заданный размер элемента, чтобы индексироватьвнутренний массив char
.Внутренние char
указатели неявно преобразуются в void
указатели интерфейса, которые, в свою очередь, неявно преобразуются в double
указатели или любой другой тип, который вы подключаете к этому массиву.
Это прекрасно работает, пока элементы тривиально копируемы .Если вам нужно, чтобы элементы сами управляли памятью, вам понадобится следующий подход:
Предоставление массива для сложных элементов данных
Если вашим объектам нужно делать пользовательские вещи при их копировании, вам необходимопредоставить пользователю средство для предоставления необходимого поведения.Это делается с помощью указателей на функции:
typedef void (*Array_callback_copy_construct)(void* this, const void* original);
typedef void (*Array_callback_destruct)(void* this);
typedef struct {
char *array;
size_t elementSize;
size_t used;
size_t size;
Array_callback_copy_construct copy_construct;
Array_callback_destruct destruct;
} Array;
void Array_init(Array *a, size_t elementSize, size_t initialSize, Array_callback_copy_construct copy_construct, Array_callback_destruct destruct);
void Array_insert(Array *a, const void* element);
const void* Array_at(Array *a, size_t index);
void Array_destruct(Array *a);
Методы Array_insert()
и Array_destruct()
теперь просто используют предоставленные пользователем функции обратного вызова для копирования и уничтожения элементов массива.
Подробнеерасширенные версии могут также использовать обратный вызов конструктора перемещения и / или обратный вызов (перемещение) назначения.Копирование + уничтожение - это минимальный набор, который вам нужен, более высокая производительность может быть достигнута с помощью более сложных обратных вызовов.
Первый метод достаточно прост, чтобы его можно было использовать в самых разных приложениях, и я хотел быне стесняйтесь использовать его.Тем не менее, уловка использования memcpy()
должна быть четко задокументирована .
Второй метод работает там, где первый метод дает сбой, но обычно он намного сложнее, чем стоит.Избегайте этого, если только вы не поймете, что это действительно единственное решение.