Я никогда не имел дела c STL, а вот сейчас кажется назрела необходимость...
Мне в программе необходимо где-то хранить различные структуры данных, считанных из некоего устройства.
Каждая структура имеет свой уникальный идентификатор.
Какой из контейнеров лучше применить для этого, и как лучше реализовать?
Я мыслю сдеалать класс типа:
class TDataArea
{
int area_id,
area_len;
char *data;
TDataArea( void );
TDataArea( int id, int len, char *buf );
~TDataArea( void );
};
и хранить экземпляры этого класса в <vector>, допустим
А при необходимости получить хранимые данные явно приводить TDataArea->data к необходимой структуре, ориентируясь по TDataArea->area_id
Использование примерно следующим образом (в сильно упрощенном виде):
vector <TDataArea> DataStorage;
...
// получение данных размером 10 байт в масиив buf.
...
// сохранение полученых данных:
TDataArea a( 1, 10, buf );
DataStorage.push_back( a );
...
// извлечение данных:
TDataArea b;
b = DataStorage[0];
TSomeStruct *s = (TSomeStruct*)b.data;
...
Корректно ли делать нечто подобное, или можно найти другое решение, более правильное и красивое?
Все зависит от того, какие возможности требуются от контейнера — ключ (map), вохиожность удалять и вставлять где-попало (list) или скорость (deque). А если нужен "динамический массив" — сделано нормально!
"SilverAurum" <30413@news.rsdn.ru> сообщил/сообщила в новостях следующее: news:824527@news.rsdn.ru... > Я никогда не имел дела c STL, а вот сейчас кажется назрела необходимость... > > Мне в программе необходимо где-то хранить различные структуры данных, считанных из некоего устройства. > Каждая структура имеет свой уникальный идентификатор. > Какой из контейнеров лучше применить для этого, и как лучше реализовать? > > Я мыслю сдеалать класс типа: > > >
> class TDataArea
> {
> int area_id,
> area_len;
> char *data;
>
> TDataArea( void );
> TDataArea( int id, int len, char *buf );
> ~TDataArea( void );
> };
>
> > и хранить экземпляры этого класса в <vector>, допустим > А при необходимости получить хранимые данные явно приводить TDataArea->data к необходимой структуре, ориентируясь по TDataArea->area_id > Использование примерно следующим образом (в сильно упрощенном виде): > >
Здравствуйте, Nazik, Вы писали:
N>Все зависит от того, какие возможности требуются от контейнера — ключ (map), вохиожность удалять и вставлять где-попало (list) или скорость (deque). А если нужен "динамический массив" — сделано нормально!
Нужен именно динамический массив, без возможности удаления-вставки где попало... Скорость работы — да, нужна. Быстрее ли будет при использовании доступа по ключу (map), чем при простом переборе всех записей в vector? Кол-во записей в массиве — в среднем около 50. Немного, но таких массивов будет множество, возможно потребуется перебор всех массивов в БД...
И еще вопрос: есть ли какие-то стандартные методы получения всех записей из массива (реализованного в vector или list,map и т.д.) с целью последующего сохранения где-либо, в файле или БД (в виде одной BLOB записи)? И есть ли возможность потом проинициализировать этой записью тот же vector или map? Или надо писать свой метод, который пройдется по всему массиву и накидает все записи в буфер? (и другой метод, который потом будет разбирать эту запись на отдельные записи и вставлять по одной...)
Здравствуйте, SilverAurum, Вы писали:
SA>Нужен именно динамический массив, без возможности удаления-вставки где попало... Скорость работы — да, нужна. Быстрее ли будет при использовании доступа по ключу (map), чем при простом переборе всех записей в vector? Кол-во записей в массиве — в среднем около 50. Немного, но таких массивов будет множество, возможно потребуется перебор всех массивов в БД...
Если вставлять только в конец, то лучше подойдет очередь (скорость доступа — const).
Если всегда осуществляется последовательный доступ через итераторы, то опять-таки вектора и очереди выигрывают (скорость доступа — const, у ассоциативного массива — O(log n)).
SA>И еще вопрос: есть ли какие-то стандартные методы получения всех записей из массива (реализованного в vector или list,map и т.д.) с целью последующего сохранения где-либо, в файле или БД (в виде одной BLOB записи)? И есть ли возможность потом проинициализировать этой записью тот же vector или map? Или надо писать свой метод, который пройдется по всему массиву и накидает все записи в буфер? (и другой метод, который потом будет разбирать эту запись на отдельные записи и вставлять по одной...)
В сущности это можно организовать, но такое решение будет зависимым от платформы. Можно использовать потоки — std::stringstream, а потом сохранять куда нужно.
Приведу пример:
class TDataArea {
int area_id; // area_len больше не нужен, т.к. используем string
std::string data; // заменяем на string, использование char* чреватоpublic:
TDataArea();
TDataArea(int id, const string& buf);
~TDataArea();
const char* getData() { return data.c_str(); }
friend ostream& operator << (ostream&, const TDataArea&);
friend istream& operator >> (istream&, const TDataArea&);
};
int main() {
vector <TDataArea> dataStorage;
DataTableGateway gate; //какой-то объект доступа к БД
gate.initialize();
for (int i = 0; i < gate.size(); ++i) {
// получение данных размером 10 байт в масиив buf.
std::string data = gate[i];
// сохранение полученых данных:
TDataArea a(i, data);
dataStorage.push_back(a);
}
// извлечение данных:
TDataArea b;
b = dataStorage[0];
TSomeStruct s(b.getData()); //если использовать в данном контексте, то лучше вообще подумать о шаблонах
// сохраняем в поток
std::stringstream s;
s << b;
// извлекаем из потока
TDataArea a;
s >> a;
// сохраняем в объект доступа к БД
gate.append(s.str().c_str());
};
ИМХО, если вы работаете с однотипными структурами, то вам лучше сделать TDataArea шаблоном.
SA>>И еще вопрос: есть ли какие-то стандартные методы получения всех записей из массива (реализованного в vector или list,map и т.д.) с целью последующего сохранения где-либо, в файле или БД (в виде одной BLOB записи)? И есть ли возможность потом проинициализировать этой записью тот же vector или map? Или надо писать свой метод, который пройдется по всему массиву и накидает все записи в буфер? (и другой метод, который потом будет разбирать эту запись на отдельные записи и вставлять по одной...)
N>В сущности это можно организовать, но такое решение будет зависимым от платформы. Можно использовать потоки — std::stringstream, а потом сохранять куда нужно. N>Приведу пример:
Это не совсем то, что я имел ввиду... Мне нужно сохранять все содержимое вектора в одной записи (или строке, в том же char*), что-то типа:
vector <TSomeData> d;
TBlobField f;
d.SaveToBase( f );
...
// и затем загружаем из базы весь вектор за один проход:
d.LoadFromBase( f );
Понятно, что можно реализовать SaveToBase и LoadFromBase самому, на основе перебора всех записей в векторе, но может быть есть уже какие-то реализованные методы, позволяющие сохранить и прочитать соджержимое всего вектора?
N>ИМХО, если вы работаете с однотипными структурами, то вам лучше сделать TDataArea шаблоном.
SA>Нужен именно динамический массив, без возможности удаления-вставки где попало... Скорость работы — да, нужна. Быстрее ли будет при использовании доступа по ключу (map), чем при простом переборе всех записей в vector?
ну map конечно быстрее , но вставлять в него намного медленней
как альтернативу map — попробуй сортированный вектор
Здравствуйте, SilverAurum, Вы писали:
SA>Это не совсем то, что я имел ввиду... Мне нужно сохранять все содержимое вектора в одной записи (или строке, в том же char*), что-то типа: SA>
SA>vector <TSomeData> d;
SA>TBlobField f;
SA>d.SaveToBase( f );
SA>...
SA>// и затем загружаем из базы весь вектор за один проход:
SA>d.LoadFromBase( f );
SA>
SA>Понятно, что можно реализовать SaveToBase и LoadFromBase самому, на основе перебора всех записей в векторе, но может быть есть уже какие-то реализованные методы, позволяющие сохранить и прочитать соджержимое всего вектора?
Для этого используется обобщенное программирование:
std::stringstream stream; //наш поток
std::istream_iterator<TSomeData> beginStream(stream); // начало потока
std::istream_iterator<TSomeData> endStream; // конец потокаstd::vector<TSomeData> d(beginStream, endStream); // прочитали из потока
std::ostream_iterator<TSomeData> streamWriter(stream); // итератор записи в потокstd::copy(d.begin(), d.end(), streamWriter); // записали в поток
Данную запись можно упростить, используя шаблоны...
SA>class TDataArea
SA>{
SA> int area_id,
SA> area_len;
SA> char *data;
SA> TDataArea( void );
SA> TDataArea( int id, int len, char *buf );
SA> ~TDataArea( void );
SA>};
SA>
SA>и хранить экземпляры этого класса в <vector>, допустим SA>А при необходимости получить хранимые данные явно приводить TDataArea->data к необходимой структуре, ориентируясь по TDataArea->area_id
Может лучше так:
class TDataArea
{
int area_id,
area_len;
union {
struct_for_id1 id1;
struct_for_id2 id2;
struct_for_id3 id3;
// ...char data[512];
};
TDataArea( void );
TDataArea( int id, int len, char *buf );
~TDataArea( void );
};