массивы — C ++ для чтения таблицы CSV в столбчатом хранилище с различными типами данных

Я хочу прочитать файл CSV, в котором содержится таблица базы данных (TPCH). Каждый файл имеет разное количество столбцов, строк и типов данных.

Например:

 file1: Int, double, char[]
file2: double, char[], int, int

Еще одно требование — каждый столбец должен находиться в массиве (для каждого столбца — массив, а не в строке).

Мое решение: В настоящее время я создаю массивы во время выполнения с новыми в зависимости от типа данных и размера файла CSV

 e.g. file1: would be int[] , double[]...

Затем я сохраняю начальный адрес моего массива как void * на карте (int, void *).

Когда я хочу прочитать значения из массива, я должен извлечь void * и привести его в соответствие с типом.

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

0

Решение

Да, указатели часто приводят к головным болям. Во-первых, я предлагаю вам использовать контейнеры STL, такие как std::vector, это сделает вашу жизнь проще. Нет надобности, даже новый компилятор C ++, потому что std::vector здесь с давних времен.

Но я не понимаю, почему вы хотите сохранить начальный адрес вашего массива. В любом случае, если вы просто хотите сохранить адрес, вы можете использовать заголовочный файл <cstdint> и использовать типы intptr_t / uintptr_tгарантированно сможет провести void*,

0

Другие решения

Это отличный пример использования variant, В C ++ 17 мы будем иметь это как часть стандартной библиотеки, но сейчас мы застряли, используя boost реализация.

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

  1. void*, Это нежелательно по многим причинам. Вы уже знаете это, поэтому я не буду углубляться в это здесь.
  2. union, Это также нежелательно при работе с объектами, которые имеют конструкторы и деструкторы. Вы должны помнить, чтобы вызывать деструкторы, и вы должны знать, чтобы вызывать конструкторы на месте. Лучше чем void*, но только едва. Предполагая, что вы имеете дело со всеми примитивными типами, std::vector<some_union_type> может быть, не так уж и плохо, но как только вы внесете динамически изменяемые строки, вы окажетесь в мире боли.
  3. Манипулирование байтами. Храните все в char[] (более конкретно, std::vector<char>) и храните метаданные о типе данных в некотором типе enum. Используйте это перечисление для приведения байтов к правильному типу. Это довольно волосатое решение, которое можно собрать вручную, но оно похоже на то, как variant обычно реализуется.
  4. Динамический полиморфизм. Создайте родительский класс, а затем дочерний класс для каждого типа данных. Динамически распределяйте дочерние классы (сохраняя их в std::unique_ptr) и получить их, делая dynamic_cast пока вы не получите правильный тип (или сохраните тип данных в enum и приведите на основе этого). Это, пожалуй, самое «высокоуровневое» решение, и, вероятно, его проще понять, чем первые три решения.
  5. Концептуальный полиморфизм. Это в основном раскатывать вручную особый случай any (упоминается в другом ответе). Шон Родитель покрывает это Вот. В вашем случае вы можете реализовать что-то вроде variant::visitor шаблон, чтобы получить данные, которые вы хотите.

Возможно используя boost::variant не выглядит так плохо в конце концов. 😉

0

По вопросам рекламы [email protected]