Помогите понять начинающему как соединить С++ и С код в одной программе?
Есть С структура базы данных:
typedef struct{unsigned int field_number;
char *field_type;
unsigned int record_number;
void *record;
unsigned int QUANT;
....
}t_db;
Т.к. длинна рекордов различна, то каждый рекорд представляет собой линейный масив из всех полей типа:
[размер данных][данные], сразу в unsigned int записано длину поля, а потом само поле (длинна одного слагаемого в массивах вычисляется на основании типа поля, а количество элементов на основе длинны поля и размера его элемента).
В С++ есть библиотека STL. В исходной С программе каждый QUANT рекордов сложен в своем линейном фрагменте памяти (некий прообраз контейнеров). Для удобства доступа к рекордам в массиве указателей *record содержаться указатели на все рекорды. Я хочу создать контейнер на QUANT рекордов с помощью STL. Проблема в моем незнании С++ (я пока запустил только Helo world) и необходимости подключения многих модулей С. Для меня пока не понятно две вещи - как в обмениваться указателями между С и С++ (записать указатели на рекорды из контейнера в указатели базы) и как управлять контейнером из С функции (к примеру добавлять/удалять рекорды и поля в них)?P.S. Замечания предложения по организации самой базы только приветствуются. Другие же реализации баз вряд ли меня заинтересуют, т.к. данная база создается не как собственно база, а как мегаобъект для подключений другим моих программ (уникальные типы полей, уникальные алгоритмы поиска, автоматическое наполнение базы новыми полями и связями между полями, поиски корреляций и автоматическая статистическая коррекция результатов).
Problem s peredachei ukazatelei ne budet - C++, kak i C ispol'zuet odin i tot zhe podhod k adresnoi arifmetike. Edinstvennoe, o chem nado pomnit' - eto to, chto operatiry new/delete ne dolzhny peresekat'sya s ispol'zovaniem _alloc/free (muhi otdel'no, kotlety otdel'no).Kak primer ispol'zovaniya konteinera: skazhem, QUANT u tebya - eto kluch v spiske (unikal'nyi dlya prostoty). Teper' ty mozhesh ob'yavit':
#include <map>
typedef std::map<unsigned int,t_db *> MYMAP;
i gde-to v kode napisat':
MYMAP myMap;
...
MYMAP::iterator it=myMap.find(index);
if(it!=myMap.end())
pRecord=it->second;
else
myMap.insert(make_pair(index,pRecord));
Спасибо genie.
Мне надо некоторое время, что бы разобраться с Вашим кодом, если будут вопросы я задам их чуть позже. Это что бы Вы не подумали, что Ваше письмо меня не заинтересовало.
>Есть С структура базы данных:
>typedef struct{unsigned int field_number;
>
> char *field_type;
>
> unsigned int record_number;
>
> void *record;
>
> unsigned int QUANT;
>
> ....
>
> }t_db;
Это база из QUANT записей? record -- массив записей? Тогда, что такое
record_number? А field_type -- это массив симболов, или строка?
>Т.к. длинна рекордов различна, то каждый рекорд представляет собой линейный масив из
>всех полей типа:
>[размер данных][данные], сразу в unsigned int записано длину поля, а потом само
>поле (длинна одного слагаемого в массивах вычисляется на основании типа поля,
>а количество элементов на основе длинны поля и размера его элемента).
База состоит из записей. Записи разной длины. Поля записи разной длины.
Поля различаются по типу (имени). Порядок полей в записи и их состав
различен для разных записей (крутое требование). Я правильно понимаю?
Теперь, что нужно сделать? Написать базу на C++, так, чтобы с ней можно
было работать из программы на C? Или, написать базу на C, так, чтобы можно
было применять к ней алгоритмы STL?>Для меня пока не понятно
>две вещи - как в обмениваться указателями между С и С++
>(записать указатели на рекорды из контейнера в указатели базы) и как
>управлять контейнером из С функции (к примеру добавлять/удалять рекорды и поля
>в них)?
Подобные проблемы решаются с помощью промежуточных интерфейсов (обёрток),
но, чтобы говорить конкретно, мне нужно лучше понять задачу.
>P.S. Замечания предложения по организации самой базы только >приветствуются. Другие же реализации
>баз вряд ли меня заинтересуют
В смысле, использования готовых баз, вроде PostgresSQL?
Здравствуйте Сергей.>Это база из QUANT записей? record -- массив записей? Тогда, что такое
>record_number? А field_type -- это массив симболов, или строка?QUANT - это длинна (в рекордах) одного блока данных базы. К примеру, в базе record_number=100 000 рекордов и QUANT=16 000, тогда база физически будет состоять из 100 000/16 000 + 1 линейных фрагментов памяти емкостью в 16 000 рекордов каждый, причем последний будет заполнен на 16 000 - 100 000%16 000. Рабочие нагрузки базы где-то 0 - 1 000 000 рекордов.
Зачем это надо? Ну охота попробовать С++ в деле (Вы его тоже, кстати, хвалили) и я читал, что применение линейных массивов ускоряет работу сортировщиков и надеюсь на некую экономию той же памяти.>База состоит из записей. Записи разной длины. Поля записи разной длины.
>Поля различаются по типу (имени). Порядок полей в записи и их состав
>различен для разных записей (крутое требование). Я правильно понимаю?
>Теперь, что нужно сделать? Написать базу на C++, так, чтобы с ней
>можно
>было работать из программы на C? Или, написать базу на C, так,
>чтобы можно
>было применять к ней алгоритмы STL?Все так кроме:
1. Порядок полей и их количество одинаково для всех рекордов (я думаю, что такая экономия памяти не стоит затрат на обработку рекордов при поиске), просто некоторые поля имеют нулевую длину.
2. Написать базу на С (в С++ я совсем новичок) с использованием контейнеров STL.>Подобные проблемы решаются с помощью промежуточных интерфейсов (обёрток),
>но, чтобы говорить конкретно, мне нужно лучше понять задачу.
А напрямую совсем нельзя? STL вроде имеет свой хороший интерфейс управления, и мне представлялось, что решив проблему с взаимной передачей указателей С <-> C++ можно работать с STL напрямую...>В смысле, использования готовых баз, вроде PostgresSQL?
Именно. Я читал статьи о форматах запросов и функциональности таких штук и пришел к выводу, что большинство функций мне не нужны, а составление запросов значительно сложнее прямой работы с полями и рекордами. Проигрывая во времени написания своей базы, я выигрываю во времени написания программ с ней работающих - а они есть основная цель.
>Рабочие нагрузки базы где-то 0
>- 1 000 000 рекордов.
Так не бывает. Это весь диапазон, а каковы среднее и стандартное
отклонение?
>я читал, что применение линейных массивов ускоряет работу
>сортировщиков и надеюсь на некую экономию той же памяти.
Ну, опять же, не само применение ускоряет, а большинство приёмов
оптимизации используют...>1. Порядок полей и их количество одинаково для всех рекордов (я думаю,
>что такая экономия памяти не стоит затрат на обработку рекордов при
>поиске), просто некоторые поля имеют нулевую длину.
А зачем тогда тип (имя) поля? Ведь, у него уже есть порядковый номер в
записи.>2. Написать базу на С (в С++ я совсем новичок) с использованием
>контейнеров STL.
Формулировочка занятная... Но смысл ясен. Точнее: написать базу в стиле
C, а использовать и на C++, и на C.
>>Подобные проблемы решаются с помощью промежуточных интерфейсов (обёрток),
>>но, чтобы говорить конкретно, мне нужно лучше понять задачу.
>А напрямую совсем нельзя? STL вроде имеет свой хороший интерфейс
>управления, и мне представлялось, что решив проблему с взаимной передачей
>указателей С <-> C++ можно работать с STL напрямую...
В STL можно обращаться с обычными массивами. Я был под впечатлением
требования непостоянного списка полей.
Видимо, то, что Вы называете передачей указателей, это тот факт, что
обычные указатели суть итераторы STL.
Пример промежуточного итерфейса (который я фамильярно называю здесь
обёрткой):
Допустим, мы хотим выполнить алгоритм STL для списка из первых
полей каждой записи (которые друг за другом лежат в обычном массиве);
длина записей разная, и переходя к первому полю следующей записи, нужно
сперва вычислить его местоположение. Алгоритм STL требует в качестве
аргумента диапазон (пару итераторов). Так вот, нам и нужно написать
такой класс-итератор, для которого применение операции ++, вызывает
вычисление положения следующего элемента и переход к нему. Если мы это
проделаем, то сможем обращаться с нашим хитрым списком первых полей как
с просто массивом (упрощаю терминологию).>>В смысле, использования готовых баз, вроде PostgresSQL?
>Именно. Я читал статьи о форматах запросов и функциональности таких штук и
>пришел к выводу, что большинство функций мне не нужны, а составление
>запросов значительно сложнее прямой работы с полями и рекордами. Проигрывая во
>времени написания своей базы, я выигрываю во времени написания программ с
>ней работающих - а они есть основная цель.
На C++ и проблема упрощения процедуры составления запросов решается
применением интерфейса-адаптера, скрыващего детали составления запроса от
прикладной программы. Ага! Вот Вы и стали сталкиваться с преимуществами
ООП по сравнению со структурным подходом.
>Так не бывает. Это весь диапазон, а каковы среднее и стандартное
>отклонение?
Норму я оцениваю в 200 000 рекордов... но диапазон 0 - 100 000 отражает лишь спектр задач, с которыми программа будет работать, меняя сами базы.>>1. Порядок полей и их количество одинаково для всех рекордов (я думаю,
>>что такая экономия памяти не стоит затрат на обработку рекордов при
>>поиске), просто некоторые поля имеют нулевую длину.
>А зачем тогда тип (имя) поля? Ведь, у него уже есть порядковый
>номер в
>записи.
Имя поля надо для ввода/вывода данных в форматах других баз и для нужд и удобства человека. Тип поля (как и его имя) задается раз в корневой структуре базы, а не в каждом рекорде, в виде char-кода.>В STL можно обращаться с обычными массивами. Я был под впечатлением
>требования непостоянного списка полей.
Для такого надо с каждым рекордом тягать еще массив бит(байт) для флага присутствия по числу полей и обрабатывать их на предмет присутствия в рекорде. Штука не сложная в реализации и мы выиграем 31 бит или (3 байт) на рекорд. В то же время, если поле имеет непостоянную длинну мы должны будем добавить тот же unsigned int для его размера, т.е выигрыш -1 бит (байт). А база нуждается в первую очередь в непостоянных полях (кроме разве что id) для всех рекордов. Я не думаю, что такая реализация будет подходящей.>Видимо, то, что Вы называете передачей указателей, это тот факт, что
>обычные указатели суть итераторы STL.
>Пример промежуточного итерфейса (который я фамильярно называю здесь
>обёрткой):
>Допустим, мы хотим выполнить алгоритм STL для списка из первых
>полей каждой записи (которые друг за другом лежат в обычном массиве);
>длина записей разная, и переходя к первому полю следующей записи, нужно
>сперва вычислить его местоположение. Алгоритм STL требует в качестве
>аргумента диапазон (пару итераторов). Так вот, нам и нужно написать
>такой класс-итератор, для которого применение операции ++, вызывает
>вычисление положения следующего элемента и переход к нему. Если мы это
>проделаем, то сможем обращаться с нашим хитрым списком первых полей как
>с просто массивом (упрощаю терминологию).Ну это очень просто, на С я это делаю так:
unsigned int get_record_lenght(unsigned int field_number,unsigned int *record)
{
unsigned int j,lenght=0;for (j=0;j<field_number;j++)
{
lenght+=record[0];
record+=record[0]+sizeof(unsigned int);
}
return lenght;
}>На C++ и проблема упрощения процедуры составления запросов решается
>применением интерфейса-адаптера, скрыващего детали составления запроса от
>прикладной программы. Ага! Вот Вы и стали сталкиваться с преимуществами
>ООП по сравнению со структурным подходом.
Почему тогда форумы пестрят вопросами об ошибках в запросах к монстрам баз данных?
Совсем забыл, функция доступа к произвольному полю рекорда:unsigned int *get_field_address(unsigned int field,unsigned int *record)
{
unsigned int j;for (j=0;j<field;j++)
record+=record[0]+sizeof(unsigned int);
return record;
}Мы не имеем указателей на обственно поля - они не нужны. В смысле затраты памяти будут field_number*record_number*sizeof(unsigned int) против record_number*sizeof(unsigned int) за field_number суммирований для доступу к полю. Если field_number=30, record_number=200 000, то мы экономим 23Mb. Если программа работает с полем, то надо один проход для создания массива указателей на нужное поле длинной меньше 1Mb. Учитывая, что база загружаеться, учитывая запросы приложения, нужные поля можно вынести в начало рекордов и придельно минимизировать затраты на доступ к данным.
>Совсем забыл, функция доступа к произвольному полю рекорда:
>
>unsigned int *get_field_address(unsigned int field,unsigned int *record)
>{
>unsigned int j;
>
>for (j=0;j<field;j++)
> record+=record[0]+sizeof(unsigned int);
>return record;
>}
>
>Мы не имеем указателей на обственно поля - они не нужны. В
>смысле затраты памяти будут field_number*record_number*sizeof(unsigned int) против record_number*sizeof(unsigned int) за field_number
>суммирований для доступу к полю. Если field_number=30, record_number=200 000, то мы
>экономим 23Mb. Если программа работает с полем, то надо один проход
>для создания массива указателей на нужное поле длинной меньше 1Mb. Учитывая,
>что база загружаеться, учитывая запросы приложения, нужные поля можно вынести в
>начало рекордов и придельно минимизировать затраты на доступ к данным.Я немного другое имел в виду. Допустим есть алгоритм на последовательности
элементов, например, один из алгоритмов STL, например, тот же поиск
find(). Как его применить к последовательности первых полей записей?
Пишем функцию, которая реализует алгоритм, а место записей вычисляем так,
как Вы описали (если это типичная работа программы, то это место нужно
оптимизировать, чтобы не вычислять лишний раз местоположение). А если
алгоритм уже реализован для обыкновенного массива (упрощяю для ясности),
то как его не переписывать?, он на вход требует массив, а у нас хитрая
последовательность. И что, если нам потом потребуется тот же алгоритм, но
не на первых/энных полях, а на первом, втором, первом, втором?
>Я немного другое имел в виду. Допустим есть алгоритм на последовательности
>элементов, например, один из алгоритмов STL, например, тот же поиск
>find(). Как его применить к последовательности первых полей записей?
>Пишем функцию, которая реализует алгоритм, а место записей вычисляем так,
>как Вы описали (если это типичная работа программы, то это место нужно
>
>оптимизировать, чтобы не вычислять лишний раз местоположение). А если
>алгоритм уже реализован для обыкновенного массива (упрощяю для ясности),
>то как его не переписывать?, он на вход требует массив, а у
>нас хитрая
>последовательность. И что, если нам потом потребуется тот же алгоритм, но
>не на первых/энных полях, а на первом, втором, первом, втором?
Не уверен, что правильно Вас понял, но если Вы имеете в виду использование встроенных в STL функций обработки массивов, то достаточно создать массив указателей на нужные поля и передать его в алгоритм. Такой прием не покатит при операциях по перемещению данных, тут надо работать исключительно с целым рекордом. Дело в том, что мои С функции рассматривают рекорд как линейную последовательность и будут вылетать в случае манипуляций с размещением фрагментов рекордов.
>Не уверен, что правильно Вас понял, но если Вы имеете в виду
>использование встроенных в STL функций обработки массивов, то достаточно создать массив
>указателей на нужные поля и передать его в алгоритм.
На создание массива уйдёт и время и место. Да и не получится с
указателями, если алгоритм обрабатывает числовую последовательность.>Такой прием
>не покатит при операциях по перемещению данных, тут надо работать исключительно
>с целым рекордом. Дело в том, что мои С функции рассматривают
>рекорд как линейную последовательность и будут вылетать в случае манипуляций с
>размещением фрагментов рекордов.
Приём итератора-адаптера прокатит и при перемещении данных...
Я хотел привести общий и одновременно простой пример. Наверное, просто
Вам нужно подольше поработать с STL, привыкнуть мыслить в её стиле.
Я, видимо, поторопился с абстрактным примером.
>На создание массива уйдёт и время и место. Да и не получится
>с
>указателями, если алгоритм обрабатывает числовую последовательность.
А иначе никак - поля разной длинны, и их позиции надо рассчитывать каждый раз заново или вынести в отдельный массив указатели (значения).
Я, правда, пока не вижу подходящих алгоритмов (не относящихся к управлению памятью) в STL для работы с подобными объектами.>Приём итератора-адаптера прокатит и при перемещении данных...
>Я хотел привести общий и одновременно простой пример. Наверное, просто
>Вам нужно подольше поработать с STL, привыкнуть мыслить в её стиле.
>Я, видимо, поторопился с абстрактным примером.
Это да, STL подключить пока не удалось :(.
>>На создание массива уйдёт и время и место. Да и не получится
>>с
>>указателями, если алгоритм обрабатывает числовую последовательность.
>А иначе никак - поля разной длинны, и их позиции надо рассчитывать
>каждый раз заново или вынести в отдельный массив указатели (значения).
О том и речь, что можно... У нас есть алгоритм, работающий только с
массивом (правильно говорить: "с диапазоном", но я упрощаю терминологию),
но у нас нет массива, а, чтобы получить новый элемент нашей
последовательности, его ещё нужно вычислить/найти, нужно ли переписывать
алгоритм? -- не нужно, мы же пишем, на C++, а не на C...
Здесь мне трудно посоветовать Вам какую-то литературу -- её видимо нет в
природе. Мне приходится по совместительству читать студенетам (это я
однажды описался, но мне понравилось это слово -- очень точное)
объектно-ориентированное программирование на 4-ом курсе физфака -- так и
пришлось самому писать "некий текст" (как я его называю), а то ведь как
им это на лекциях рассказывать -- осатанеть же можно. Если хотите почить
этот пёрл изящной словесности, то могу выслать, или весь, или выдрать
страницы про STL; он на русском (разговорном) в pdf, напишите мне на
zbl@gmail.ru -- вышлю c++guide-2.2.1.tar.bz2 227 килобайт.>Я, правда, пока не вижу подходящих алгоритмов (не относящихся к управлению памятью)
>в STL для работы с подобными объектами.
Вся STL предназначена для работы с такими объектами... Ну сами посудите:
например, find() -- стоило бы его помещать в отдельную библиотеку, его
реализация из двух строк состоит. Ага! Второй раз Вы столкнулись с
преимуществом объектного подхода над структурным (правда STL -- не
объектно-ориентированная библиотека, в строгом смысле этого слова, но,
конечно, она предназначена для использования в объктно-ориентированных
программах).>STL подключить пока не удалось :(.
// C++
#include <cstdlib>
#include <iostream>
#include <string>
// STL
#include <vector>
using namespace std;
int main(){
vector<int> vi;
for( unsigned int k= 0; k < 10; k++ ) vi.push_back( k );
for( unsigned int k= 0; k < vi.size(); k++ )
cout << "[" << k << "] " << vi[k] << endl;
return EXIT_SUCCESS;
}bash$ c++ -Wall -o helloSTL helloSTL.c++
bash$ ./helloSTL
Не проверялось.
Здравствуйте.В основном вопрос относиться к Сергею, но если кто прочитает топик и захочет высказаться, то ваша помощь будет не лишней.
Я переписал базу, ориентировав ее на использование контейнеров. База написана на С, и к моменту, когда вы ответите уже будет работать (я надеюсь). Я создал свой вариант контейнера (тоже на С) для хранения объектов, так что подключить STL будет легко. Сейчас я использую 3 функции для организации хранения данных в контейнере:
//This function init container
char alloc_container(unsigned int container_capacity,unsigned int max_object_lenght,float estimated_object_increasing,t_container *container);//This function add object to container
char add_object_to_container(unsigned int object_lenght,void *object_address,t_container *container);//This function replace record in container
char replace_object_in_container(unsigned int object_displacement,unsigned int old_object_lenght,unsigned int new_object_length,void *new_object,t_container *container);и структуру самого контейнера (все как в STL)
//It is a container structure
typedef struct {
unsigned int container_size; //really used size
unsigned int container_capacity; //asked size of element
unsigned int max_object_lenght; //maximal lenght of one object in container
unsigned int objects_number; //number of objects in container
float estimated_object_increasing; //size of container grouth after its overflow
}t_container; //container
Данные дописываться в конец (первый свободный байт после размера контейнера).
Я сравню скорости обоих решений (надеюсь, STL будет быстрее).Если это не долго, то напишите как вызвать STL по шаблонам этих функций из С программы?
Я отсылал Вам 2 письма с просьбой прислать Ваши лекции на yakovenko_a@ukr.net, но ответа так и не пришло. Если не трудно, то перешлите их мне.
Заранее благодарен.
>Я создал свой вариант контейнера (тоже на С) для хранения объектов,
На сколько я вижу, лишний труд: можно было обойтись и старой реализацией базы.
>так что подключить STL будет легко. Сейчас я использую 3 функции
>для организации хранения данных в контейнере:
>и структуру самого контейнера (все как в STL)
>Я сравню скорости обоих решений (надеюсь, STL будет быстрее).
Если на C реализовать контейнеры STL, то они не будут контейнерами STL, и
сравнивать будет нечего. Если есть желание проверить эффективность
реализации STL, то лучше написать тестовую программку, решающую
простенькую задачку, на C и на STL и сравнить. Но, вообще-то, это пустое
занятие, хотя и интересное для досуга. Пустое, потому что это уже
многократно проделали сами разработчики STL.>Если это не долго, то напишите как вызвать STL по шаблонам этих
>функций из С программы?
Вах-вах... это ни к чему совершенно.
Наверно надо задачку упростить до безобразия, а уж Вы бы потом её решение
переиначивали на свою хитробазу, а то, я гляжу, слишком много лишнего
труда получается.
Вот моя формулировка, уточните, если что не так:
Дан линейный массив целых чисел, который на самом деле есть набор записей
переменной длины; значение первого поля записи -- количество полей в ней.
int db[]= {
5, 1, 2, 0, 0, 0,
3, 1, 2, 0,
4, 1, 2, 0, 0 };
Одна из задач: сложить значения первых полей каждой записи (1 + 1 + 1 == 3),
используя алгоритм acumulate() из STL.
Если формулировка Вас устраивает, то приведу решение.>Я отсылал Вам 2 письма с просьбой прислать Ваши лекции на yakovenko_a@ukr.net,
>но ответа так и не пришло. Если не трудно, то перешлите
>их мне.
Выслал с другого ящика.
Труд был не лишним:
1. Я понял причину организации (и стратегию реализации) некоторых типов итераторов в STL и доброй половины алгоритмов.
2. База принципиально поменяла формат - она сможет работать и в тех случаях, когда размер базы не помещается в оперативку.
3. Уже мои контейнеры ускорили загрузку 200 000 - рекордового текстового файла (600М) где-то на 30%. Потребление памяти уменьшалось почти в 2 (!) раза (последний факт взят из системного монитора, и понять его причины я пока не могу).Да, идея сравнения на такой простой задаче выглядит заманчиво. Разработчики, конечно, все пробовали, но мои коды далеко не так оптимальны, как код профессионалов и потому такое сравнение имеет смысл.
Только я предлагаю не читать файл, а генерировать рандомно поток данных, которые будет размещать STL и мое С решение. Тут один вопрос, эффективность моего алгоритма сильно зависит от параметра ожидаемого роста контейнера и предела его роста перед созданием нового контейнера, а как быть с STL?За лекции большое спасибо, читаю пока с увлечением. К примеру с vim я никогда не работал, а KDeveloper есть далеко не везде.
>Труд был не лишним:
Вам виднее.>1. Я понял причину организации (и стратегию реализации) некоторых типов итераторов в
>STL и доброй половины алгоритмов.
А как с вопросом, что такое итератор есть?>2. База принципиально поменяла формат - она сможет работать и в тех
>случаях, когда размер базы не помещается в оперативку.
Это проблема ОС а не прикладной программы.>Только я предлагаю не читать файл, а генерировать рандомно поток данных, которые
>будет размещать STL и мое С решение. Тут один вопрос, эффективность
>моего алгоритма сильно зависит от параметра ожидаемого роста контейнера и предела
>его роста перед созданием нового контейнера, а как быть с STL?
Не понял вопроса.>За лекции большое спасибо, читаю пока с увлечением. К примеру с vim
>я никогда не работал, а KDeveloper есть далеко не везде.
Я сам когда-то начал с KDevelop, и считаю, что для начинающих (при
соблюдении определённых условий) лучше принять такую последовательность
изучения: gvim(emacs, nedit, cooledit,...) -> make -> autoconf -> gtdesigner -> kdevelop.
>А как с вопросом, что такое итератор есть?
Не уверен, что в STL именно так, но похоже итератор - это такой хитрый указатель, который сам по себе ничего не значит, но позволяет получить данные, зная адрес контейнера и что-то связанное с размерами объектов.
У себя я брал за итератор функцию вычисления смещения от начала контейнера, если размеры объектов записаны в массив. Такая функция независима от указателя на контейнер и позволяет работать с объектами как обычная адресная арифметика.>Не понял вопроса.
Похожие параметры должны быть и в STL, но какие их значения там?Да, vim похоже достаточно удобный для работы. Ищу похожие команды и в KDeveloper. :)
>>А как с вопросом, что такое итератор есть?
>Не уверен, что в STL именно так, но похоже итератор - это
>такой хитрый указатель, который сам по себе ничего не значит, но
>позволяет получить данные, зная адрес контейнера и что-то связанное с размерами
>объектов.
>У себя я брал за итератор функцию вычисления смещения от начала контейнера,
>если размеры объектов записаны в массив. Такая функция независима от указателя
>на контейнер и позволяет работать с объектами как обычная адресная арифметика.
Есть понятие итератора вообще и итеретора STL. Так вот обычная функция не
может быть итератором STL (но может быть итератором с точки зрения другой
библиотеки).
>>Не понял вопроса.
>Похожие параметры должны быть и в STL, но какие их значения там?
С трудом понимаю вопрос. Формулируйте такие вещи как задачу: есть
контейнер, например, вектор; мы заполняем его потоком данных; количество
данных приблизительно известно; как оптимизировать использование
памяти? Ответ: воспользоватся предварительным резервированием, reserve().
Выполнение этой опереции для вектора не приведёт к немедленному
выделению памяти, но вектор будет испольрзовать полученную информацию,
так разумно, как только это удалось реализовать разработчикам STL.>Да, vim похоже достаточно удобный для работы. Ищу похожие команды и в
>KDeveloper. :)
Когда не найдёте, имейте в виду, что vi/vim существует 30 лет. За этот
гиганский промежуток времени в нём сохранилось только то, что действительно
упрощает и ускоряет разработку. Vim понастоящему "средство быстрой
разработки". Но он имеет недостатки, главный из которых -- сложность в
изучении.
>С трудом понимаю вопрос. Формулируйте такие вещи как задачу: есть
>контейнер, например, вектор; мы заполняем его потоком данных; количество
>данных приблизительно известно; как оптимизировать использование
>памяти? Ответ: воспользоватся предварительным резервированием, reserve().
>Выполнение этой опереции для вектора не приведёт к немедленному
>выделению памяти, но вектор будет испольрзовать полученную информацию,
>так разумно, как только это удалось реализовать разработчикам STL.Ага, это уже интересно. Вы имеете ввиду что функция reserve() поместит контейнер не в первую попавшеюся область памяти, с подходящим размером, а в зону, где возможен некоторый рост длинны без копирования содержимого памяти? А как объяснить системе (без прямого выделения) что помещать в эту зону ничего не надо (если можно поместить куда-то еще)? Достаточно ли для этого резервировать память в конце ОЗУ (я читал, что malloc выделяет первый попавшийся достаточный фрагмент идя от начала ОЗУ до ее конца)?
Я с Вами соглашусь в другом - глупо гонятся за профессионалами. STL выглядит очень полезной и заманчивой библиотекой. Но что мне делать со своей базой? Она написана на С и уже работает. Она умеет разбивать базу на набор контейнеров и работать с ними отдельно, ее жалко выбрасывать, даже если учитывать, что переписывания на С++ уже рабочего кода не отнимет много времени. Да и процессы подключаемые к ней будут написаны на С - там очень интенсивные вычисления, но относительно небольшая длинна исходного кода + они тоже уже работают. Как совместить два хороших, родственных языка в одном приложении (хотя бы на уроне подключаемых процессов с общими полями данных)?И еще вопрос о vim.
Он хорош, если параллельно открыто 2-3 файла, а если весь проект из 20-25 файлов, причем одновременно редактировать надо где-то половину из них. В КД есть панелька с именами файлов - просто кликнешь, а в vim есть что-то такое? (Sorry, если там все описано, а я еще просто не дочитал).
Спасибо.
>Я сам когда-то начал с KDevelop, и считаю, что для начинающих (при
>соблюдении определённых условий) лучше принять такую последовательность
>изучения: gvim(emacs, nedit, cooledit,...) -> make -> autoconf -> gtdesigner -> kdevelop.для начинающих я бы точно убрал autoconf из числа пайщиков акционеров :) для хорошо понимающего процесс программиста autoconf может сослужить хорошую службу. для всех остальных - это Смерть. равно как и для последующих пользователей криво сделанных configure.
// wbr
>>Я сам когда-то начал с KDevelop, и считаю, что для начинающих (при
>>соблюдении определённых условий) лучше принять такую последовательность
>>изучения: gvim(emacs, nedit, cooledit,...) -> make -> autoconf -> gtdesigner -> kdevelop.
>
>для начинающих я бы точно убрал autoconf из числа пайщиков акционеров :)
Соглашусь с уточнением в том смысле, что если человек не планирует делать свой код проектом open source. В противном случае ему стоит хотя бы знать, что такое autoconf, какую проблему он решает и уметь составить configure из
набора стандартных макросов, входящего в дистрибутив Red Hat. Потом,
добравщийся до решения проблем, для решения которых предназначен autoconf,
наверно, уже не начинающий, а продолжающий.
>Соглашусь с уточнением в том смысле, что если человек не планирует делать
>свой код проектом open source. В противном случае ему стоит хотя
>бы знать, что такое autoconf, какую проблему он решает и уметь
>составить configure из
>набора стандартных макросов, входящего в дистрибутив Red Hat. Потом,
>добравщийся до решения проблем, для решения которых предназначен autoconf,
>наверно, уже не начинающий, а продолжающий.согласен. я лишь имел ввиду, что для новичка autoconf - это не самое лучшее решение. тем более, что afaiu человеческой документации на autotools как не было так и нет -> "каждый пишет как он дышит" (c)..
ps: но на фоне кустарных писулек a'la configure autotools все-таки выигрывают. это конечно зло, но оно тут живет уже давно и как-то но обкатано :) взять, хотя бы, openssl.. поубывафф бы!
// wbr
>"каждый пишет как он дышит" (c)..
(c) Игорь Облаков? Или это было известно до него?>ps: но на фоне кустарных писулек a'la configure autotools все-таки выигрывают. это
>конечно зло, но оно тут живет уже давно и как-то но
>обкатано :) взять, хотя бы, openssl.. поубывафф бы!
Я тут, как не трудно видеть, обожаю трепаться на глобальные темы. Так вот,
первый раз вижу, чтобы кто-то был согласен с утверждением: "Если живёт, то
уже достойно внимания, как бы уродливо, как бы криво не было". Удивлён.
>>"каждый пишет как он дышит" (c)..
>(c) Игорь Облаков? Или это было известно до него?afair это таки Булат Окуджава.. ;)
>>ps: но на фоне кустарных писулек a'la configure autotools все-таки выигрывают. это
>>конечно зло, но оно тут живет уже давно и как-то но
>>обкатано :) взять, хотя бы, openssl.. поубывафф бы!
>Я тут, как не трудно видеть, обожаю трепаться на глобальные темы. Так
>вот,
>первый раз вижу, чтобы кто-то был согласен с утверждением: "Если живёт, то
>уже достойно внимания, как бы уродливо, как бы криво не было". Удивлён.ключевое слово - если действительно живет. при всех недостатках autotools (основным и главным из которых являются его горе-пользователи) он таки работает. и при грамотно написанном скрипте он работает вполне прилично. при всем прочем, autotools все-таки поддерживаются и развиваются, что весьма и весьма немаловажно. so применительно к данному продукту термин "как-то но живет" вполне употребим.
самое забавное начинается, когда вам нужно сделать cross-build какого-то пакета. скажем, с NetBSD/i386 на Linux/arm32 (Intel PXA25x). вот тут начинаются все веселости и приседания.
хороший и простой пример - thttpd. базируется на autoconf. процесс сборки банален - ставим cross-build gcc на Linux/arm32 + Linux emulation, задаем нужные кросс CC и пр. переменные окружения и запускаем родной configure. на выходе получаем рабочий Makefile, который действительно собирает проект без всяких проблем. просто прелесть!
средний пример - samba. тут все веселее бо в процессе сборки собираются служебные приложения, используемые при самой сборке. по понятным причинам configure с исправленными CC & K тут уже не прокатывает :( приходится приседать.
отвратительный пример - OpenSSL. он вообще построен на базе своего, наколеночного доморощенного движка a'la configure, который застрелиться можно заставлять использовать конкретно заданные cc, ld и пр. кросс-сборка родными средствами превращается в шаманский танец с исправлением движка, долгим и нудным тестированием и пр. хотя был бы там autoconf все могло бы быть на порядок проще.
если оценивать autoconf с точки зрения сравнения с другими подходами к управлению сборкой проекта, зачастую, все выглядит далеко не так уж и плохо :) в плане что бывает гооораздо хуже. so уж лучше все-таки какой-никакой но autoconf, чем чьи-то кривые руки.
другое дело, что инструмент весьма нетривиальный и требует очень хорошего понимания производимых действий и из последствий для конечного пользователя.
// wbr
>С трудом понимаю вопрос. Формулируйте такие вещи как задачу: есть
>контейнер, например, вектор; мы заполняем его потоком данных; количество
>данных приблизительно известно; как оптимизировать использование
>памяти? Ответ: воспользоватся предварительным резервированием, reserve().
>Выполнение этой опереции для вектора не приведёт к немедленному
>выделению памяти, но вектор будет испольрзовать полученную информацию,
>так разумно, как только это удалось реализовать разработчикам STL.Ага, это уже интересно. Вы имеете ввиду что функция reserve() поместит контейнер не в первую попавшеюся область памяти, с подходящим размером, а в зону, где возможен некоторый рост длинны без копирования содержимого памяти? А как объяснить системе (без прямого выделения) что помещать в эту зону ничего не надо (если можно поместить куда-то еще)? Достаточно ли для этого резервировать память в конце ОЗУ (я читал, что malloc выделяет первый попавшийся достаточный фрагмент идя от начала ОЗУ до ее конца)?
Я с Вами соглашусь в другом - глупо гонятся за профессионалами. STL выглядит очень полезной и заманчивой библиотекой. Но что мне делать со своей базой? Она написана на С и уже работает. Она умеет разбивать базу на набор контейнеров и работать с ними отдельно, ее жалко выбрасывать, даже если учитывать, что переписывания на С++ уже рабочего кода не отнимет много времени. Да и процессы подключаемые к ней будут написаны на С - там очень интенсивные вычисления, но относительно небольшая длинна исходного кода + они тоже уже работают. Как совместить два хороших, родственных языка в одном приложении (хотя бы на уроне подключаемых процессов с общими полями данных)?И еще вопрос о vim.
Он хорош, если параллельно открыто 2-3 файла, а если весь проект из 20-25 файлов, причем одновременно редактировать надо где-то половину из них. В КД есть панелька с именами файлов - просто кликнешь, а в vim есть что-то такое? (Sorry, если там все описано, а я еще просто не дочитал).
>Вы имеете ввиду что функция reserve() поместит контейнер
>не в первую попавшеюся область памяти, с подходящим размером, а в
>зону, где возможен некоторый рост длинны без копирования содержимого памяти? А
>как объяснить системе (без прямого выделения) что помещать в эту зону
>ничего не надо (если можно поместить куда-то еще)? Достаточно ли для
>этого резервировать память в конце ОЗУ (я читал, что malloc выделяет
>первый попавшийся достаточный фрагмент идя от начала ОЗУ до ее конца)?
Это всё детали реализации, на которые не стоит полягаться. Сегодня может
быть так, завтра -- иначе.>Я с Вами соглашусь в другом - глупо гонятся за профессионалами. STL
>выглядит очень полезной и заманчивой библиотекой. Но что мне делать со
>своей базой? Она написана на С и уже работает. Она умеет
>разбивать базу на набор контейнеров и работать с ними отдельно, ее
>жалко выбрасывать, даже если учитывать, что переписывания на С++ уже рабочего
>кода не отнимет много времени. Да и процессы подключаемые к ней
>будут написаны на С - там очень интенсивные вычисления, но относительно
>небольшая длинна исходного кода + они тоже уже работают. Как совместить
>два хороших, родственных языка в одном приложении (хотя бы на уроне
>подключаемых процессов с общими полями данных)?
Вы, наверно, пролистнули одно место выше с задачей про массив из целых
чисел. Я о том и хотел поговорить: как, не переписывая базу, с ней
работать из C++ программы. Только, стоит речь вести об упрощённом
примере, а не о реальной задаче -- иначе потратим лишнее время/усилия.>И еще вопрос о vim.
>Он хорош, если параллельно открыто 2-3 файла, а если весь проект из
>20-25 файлов, причем одновременно редактировать надо где-то половину из них. В
>КД есть панелька с именами файлов - просто кликнешь, а в
>vim есть что-то такое? (Sorry, если там все описано, а я
>еще просто не дочитал).
Здесь есть особенность vim (как и текстового интерфейса по сравнению с
графическим): не будет постоянно видно списка открытых буферов (в
Emacs видно). Конечно, есть возможность это реализовать средствами vim (он
может всё), но трудно, а главное -- не нужно. Если хотите посмотреть
список буферов, есть
:ls
Если хотите переключиться куда-то, то нужно сначала сообразить, куда, а
потом ввести команду-кондидат для автозаполнения. Например, чтобы в списке
prog1_blabla.c++ prog2_albalb.c++ prog3_ablabl.c++ ... перейти ко второй
позиции, нужно ввести
:b *2*
и нажать на Tab. Можно показать список кандидатов на автозаполнение,
быстро выбрать элемент этого списка, ну и всё-всё-всё. Только, всё-таки
это очень напрягает привыкших к граф. интерфейсу.
>Вы, наверно, пролистнули одно место выше с задачей про массив из целых
>
>чисел. Я о том и хотел поговорить: как, не переписывая базу, с
>ней
>работать из C++ программы. Только, стоит речь вести об упрощённом
>примере, а не о реальной задаче -- иначе потратим лишнее время/усилия.ОК, вот код С программы:
#include "container.h"//6s of AthlonXP1700 and 150M RAM undew Windows
int main()
{
unsigned int object[11],i,count,object_lenght;
const unsigned int number[]={0,1,2,3,4,5,6,7,8,9};
t_container *container;
if (!(alloc_container(0,0.1,&container))) return FALSE;for (count=0;count<500000;count++)
for (i=0;i<10;)
{
memcpy(&object,&i,sizeof(unsigned int));
memcpy((void*)((unsigned int)object+sizeof(unsigned int)),number,object_lenght=sizeof(unsigned int)*++i);
if (!(add_object_to_container(object_lenght,object,&container))) goto ERROR;
}
printf ("All %d object stored successfuly\n",count);return TRUE;
ERROR:
printf ("Only %d object (from 500 000) stored successfuly\n",count);
return FALSE;
}
Вот container.h#include "system.h"
//It is a container structure
typedef struct {
unsigned int size; //really used size
unsigned int capacity; //asked size
float estimated_object_increasing; //number of container grouth (in parts of total objects in container) after its overflow
}t_container; //container
//This function init container
char alloc_container(unsigned int container_capacity,float estimated_object_increasing,t_container **container);//This function add object to container
char add_object_to_container(unsigned int object_lenght,void *object_address,t_container **container);//This function replace record in container
char replace_object_in_container(unsigned int object_displacement,unsigned int old_object_lenght,unsigned int new_object_length,void *new_object,t_container *container);
>Здесь есть особенность vim (как и текстового интерфейса по сравнению с
>графическим): не будет постоянно видно списка открытых буферов (в
>Emacs видно). Конечно, есть возможность это реализовать средствами vim (он
>может всё), но трудно, а главное -- не нужно. Если хотите посмотреть
>
>список буферов, есть
>:ls
>Если хотите переключиться куда-то, то нужно сначала сообразить, куда, а
>потом ввести команду-кондидат для автозаполнения. Например, чтобы в списке
>prog1_blabla.c++ prog2_albalb.c++ prog3_ablabl.c++ ... перейти ко второй
>позиции, нужно ввести
>:b *2*
>и нажать на Tab. Можно показать список кандидатов на автозаполнение,
>быстро выбрать элемент этого списка, ну и всё-всё-всё. Только, всё-таки
>это очень напрягает привыкших к граф. интерфейсу.Да есть немного - руки к мышке тянутся, но терпеть можно. Привыкаю потихоньку :).
А вот КД есть автодополнение команд (особенно для структур со множеством вложений), а vim такая функция есть?
STL работает в 2 раза быстрее моей реализации (я правда обломился размещать свои контейнеры в "верхних слоях" памяти). Ну, еще пол секунды уйдет на копирование данных в обьект... А в STL используют realloc для перевыделения памяти или malloc-memcpy-free или что-то свое?
Вот в чем жесткий минус объектов вообще - не чувствуешь затрат как в С.
В STL несколько типов контейнеров, которые подходят по-разному для разных задач, но что стоят преобразования одного в другой и как сравнить два решения: операция в лоб с исходным типом или конвертация->оптимальная операция->конвертация.
Абсолютно реальная задача есть контейнер длинны begin-end с N объектами, нам надо увеличить размер M объекта. По определенным соображениям (затраты на разыменования к примеру) у нас основним хранилищем данных будет вектор. Есть три решения переконвертить контейнер в list, сделать копию в list или работать с вектором. Какие должны быть N, M, begin-end и сколько изменений объектов ожидать что бы выбрать тот или другой алгоритм?
Вообщем вопросов пока много, но некое представление уже есть, спасибо Сергей.#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>using namespace std;
//3s AthlonXP1700 and 120M memory
int main()
{
unsigned int i,count,k;
const unsigned int number[]={0,1,2,3,4,5,6,7,8,9};
vector<unsigned int>cntr;
for (count=0;count<500000;count++)
for (i=0;i<10;i++)
{
cntr.push_back(i*sizeof(unsigned int));
for (k=0;k<i+1;k++)
cntr.push_back(number[k]);
}
cout << "All " << count << " objects stored successfuly\n" << endl;return EXIT_SUCCESS;
}
>А в STL используют realloc для
>перевыделения памяти или malloc-memcpy-free или что-то свое?
Не интересовался, опять же потому, что это сильно зависит от реализации.
STL, кстати, позволяет подставить свой алгоритм распределения памяти
(с помощью аллокаторов).>Вот в чем жесткий минус объектов вообще - не чувствуешь затрат как
>в С.
А вот в чём жёсткий минус C -- не чувствуешь затрат как в ассемблере...>Абсолютно реальная задача есть контейнер длинны begin-end с N объектами, нам надо
>увеличить размер M объекта. По определенным соображениям (затраты на разыменования к
>примеру) у нас основним хранилищем данных будет вектор.
Странные соображения: во всех контейнерах STL доступ -- это разыменование
указателя. Если часто удаляем/добавляем в середину, то нужно использовать list.
Мне опять не понятно -- контейнер написан на STL, или это хитро
размеченный линейный массив, или это написанный на C контейнер STL?
Ну с аллокаторами я пока не хочу завязываться - чуть лучше разберусь с дефолтным STL, потом очередь дойдет и до аллокаторов.Ну ассемблер это уже для особых случаев, а так С достаточно оказателен в отношении затрат.
Простите за неразборчивые выражения мысли. Под контейнерами мы будем понимать контейнеры STL. Можно работать с char вектором, запоминая где-то и в unsigned int длинны обьектов. Но задача кажеться стандартной - содержать массив обьектов произвольной длинны. Меня интересует, как заставить библиотеку работать, когда четкой параметризации шаблонов контейнеров нет.
Конкретная задача.
Поле базы несет информацию о координатах атомов. Это означает список из триплетов типа float (x,y,z). Но у разных соединений разное количество атомов и длинна списка соответственно разная. Как мне поместить координаты в контейнер, что бы операция ++ и -- передвигала итератор не на один триплет, а на столько триплетов, сколько атомов в соединении и что бы остальные операции доступа, удаления извлечения тоже узнавали конкретный список, а не отдельный набор из трех координат.
Спасибо.